diff --git a/boards/shields/nrf7002eb/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/boards/shields/nrf7002eb/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..89e3d5c4c9a --- /dev/null +++ b/boards/shields/nrf7002eb/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Only GPIOs 1..11 are supported for PORT1 in nRF54H20DK board, for now + * remove this as Wi-Fi SR co-existence is not yet supported on this board. + * The external SR RF switch may not even be present on this board. + */ +&nrf70 { + /delete-property/ srrf-switch-gpios; +}; diff --git a/drivers/clock_control/clock_control_nrf2_hfxo.c b/drivers/clock_control/clock_control_nrf2_hfxo.c index 977c0aaa0d6..eae419f18bb 100644 --- a/drivers/clock_control/clock_control_nrf2_hfxo.c +++ b/drivers/clock_control/clock_control_nrf2_hfxo.c @@ -21,6 +21,9 @@ struct dev_data_hfxo { onoff_notify_fn notify; struct k_timer timer; sys_snode_t hfxo_node; +#if defined(CONFIG_ZERO_LATENCY_IRQS) + uint16_t request_count; +#endif /* CONFIG_ZERO_LATENCY_IRQS */ }; struct dev_config_hfxo { @@ -29,6 +32,23 @@ struct dev_config_hfxo { k_timeout_t start_up_time; }; +#if defined(CONFIG_ZERO_LATENCY_IRQS) +static uint32_t full_irq_lock(void) +{ + uint32_t mcu_critical_state; + + mcu_critical_state = __get_PRIMASK(); + __disable_irq(); + + return mcu_critical_state; +} + +static void full_irq_unlock(uint32_t mcu_critical_state) +{ + __set_PRIMASK(mcu_critical_state); +} +#endif /* CONFIG_ZERO_LATENCY_IRQS */ + static void hfxo_start_up_timer_handler(struct k_timer *timer) { struct dev_data_hfxo *dev_data = @@ -48,6 +68,40 @@ static void hfxo_start_up_timer_handler(struct k_timer *timer) } } +static void start_hfxo(struct dev_data_hfxo *dev_data) +{ + nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED); + soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); + nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO); +} + +static void request_hfxo(struct dev_data_hfxo *dev_data) +{ +#if defined(CONFIG_ZERO_LATENCY_IRQS) + unsigned int key; + + key = full_irq_lock(); + if (dev_data->request_count == 0) { + start_hfxo(dev_data); + } + + dev_data->request_count++; + full_irq_unlock(key); +#else + start_hfxo(dev_data); +#endif /* CONFIG_ZERO_LATENCY_IRQS */ +} + +#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) +void nrf_clock_control_hfxo_request(void) +{ + const struct device *dev = DEVICE_DT_INST_GET(0); + struct dev_data_hfxo *dev_data = dev->data; + + request_hfxo(dev_data); +} +#endif /* CONFIG_ZERO_LATENCY_IRQS */ + static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) { struct dev_data_hfxo *dev_data = @@ -56,10 +110,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) const struct dev_config_hfxo *dev_config = dev->config; dev_data->notify = notify; - - nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED); - soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); - nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO); + request_hfxo(dev_data); /* Due to a hardware issue, the HFXOSTARTED event is currently * unreliable. Hence the timer is used to simply wait the expected @@ -68,13 +119,53 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) k_timer_start(&dev_data->timer, dev_config->start_up_time, K_NO_WAIT); } +static void stop_hfxo(struct dev_data_hfxo *dev_data) +{ + nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO); + soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); +} + +static void release_hfxo(struct dev_data_hfxo *dev_data) +{ +#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) + unsigned int key; + + key = full_irq_lock(); + if (dev_data->request_count < 1) { + full_irq_unlock(key); + /* Misuse of the API, release without request? */ + __ASSERT_NO_MSG(false); + /* In case asserts are disabled early return due to no requests pending */ + return; + } + + dev_data->request_count--; + if (dev_data->request_count < 1) { + stop_hfxo(dev_data); + } + + full_irq_unlock(key); +#else + stop_hfxo(dev_data); +#endif /* CONFIG_ZERO_LATENCY_IRQS */ +} + +#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) +void nrf_clock_control_hfxo_release(void) +{ + const struct device *dev = DEVICE_DT_INST_GET(0); + struct dev_data_hfxo *dev_data = dev->data; + + release_hfxo(dev_data); +} +#endif /* IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) */ + static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) { struct dev_data_hfxo *dev_data = CONTAINER_OF(mgr, struct dev_data_hfxo, mgr); - nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO); - soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); + release_hfxo(dev_data); notify(mgr, 0); } diff --git a/drivers/wifi/nrf_wifi/Kconfig.nrfwifi b/drivers/wifi/nrf_wifi/Kconfig.nrfwifi index 45a22b7e7fa..0bb9b21b314 100644 --- a/drivers/wifi/nrf_wifi/Kconfig.nrfwifi +++ b/drivers/wifi/nrf_wifi/Kconfig.nrfwifi @@ -201,6 +201,12 @@ config NRF70_SR_COEX config NRF70_SR_COEX_RF_SWITCH bool "GPIO configuration to control SR side RF switch position" + depends on $(dt_node_has_prop,nrf70, srrf-switch-gpios) + depends on NRF70_SR_COEX + help + Select this option to enable GPIO configuration to control SR side RF switch position. + If this GPIO is asserted (1), the SR side RF switch is connected to the Wi-Fi side (shared antenna). + If this GPIO is de-asserted (0), the SR side RF switch is connected to the SR side (separate antenna). config NRF70_WORKQ_STACK_SIZE int "Stack size for workqueue" diff --git a/drivers/wifi/nrf_wifi/src/coex.c b/drivers/wifi/nrf_wifi/src/coex.c index 7bb89a07e9e..947bf8511a2 100644 --- a/drivers/wifi/nrf_wifi/src/coex.c +++ b/drivers/wifi/nrf_wifi/src/coex.c @@ -247,10 +247,8 @@ int nrf_wifi_config_sr_switch(bool separate_antennas) if (separate_antennas) { gpio_pin_set_dt(&sr_rf_switch_spec, 0x0); - LOG_INF("GPIO P1.10 set to 0"); } else { gpio_pin_set_dt(&sr_rf_switch_spec, 0x1); - LOG_INF("GPIO P1.10 set to 1"); } return 0; diff --git a/include/zephyr/drivers/clock_control/nrf_clock_control.h b/include/zephyr/drivers/clock_control/nrf_clock_control.h index 27ab518920f..8d9bcbe3441 100644 --- a/include/zephyr/drivers/clock_control/nrf_clock_control.h +++ b/include/zephyr/drivers/clock_control/nrf_clock_control.h @@ -317,6 +317,30 @@ int nrf_clock_control_cancel_or_release(const struct device *dev, return api->cancel_or_release(dev, spec, cli); } +/** @brief Request the HFXO from Zero Latency Interrupt context. + * + * Function is optimized for use in Zero Latency Interrupt context. + * It does not give notification when the HFXO is ready, so each + * user must put the request early enough to make sure the HFXO + * ramp-up has finished on time. + * + * This function uses reference counting so the caller must ensure + * that every nrf_clock_control_hfxo_request() call has a matching + * nrf_clock_control_hfxo_release() call. + */ +void nrf_clock_control_hfxo_request(void); + +/** @brief Release the HFXO from Zero Latency Interrupt context. + * + * Function is optimized for use in Zero Latency Interrupt context. + * + * Calls to this function must be coupled with prior calls + * to nrf_clock_control_hfxo_request(), because it uses basic + * reference counting to make sure the HFXO is released when + * there are no more pending requests. + */ +void nrf_clock_control_hfxo_release(void); + #endif /* defined(CONFIG_CLOCK_CONTROL_NRF2) */ /** @brief Get clock frequency that is used for the given node. diff --git a/modules/openthread/platform/diag.c b/modules/openthread/platform/diag.c index 23ea3b97986..edf8ad09dd5 100644 --- a/modules/openthread/platform/diag.c +++ b/modules/openthread/platform/diag.c @@ -8,20 +8,44 @@ #include #include +#include #include +#include #include "platform-zephyr.h" #include "zephyr/sys/util.h" +enum { + DIAG_TRANSMIT_MODE_IDLE, + DIAG_TRANSMIT_MODE_PACKETS, + DIAG_TRANSMIT_MODE_CARRIER, + DIAG_TRANSMIT_MODE_MODCARRIER + +} diag_trasmit_mode; + /** * Diagnostics mode variables. * */ + static bool sDiagMode; static void *sDiagCallbackContext; static otPlatDiagOutputCallback sDiagOutputCallback; +static uint8_t sTransmitMode = DIAG_TRANSMIT_MODE_IDLE; +static uint8_t sChannel = 20; +static uint32_t sTxPeriod = 1; +static int32_t sTxCount; +static int32_t sTxRequestedCount = 1; static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); +static otError processTransmit(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); + +static otError parse_long(char *aArgs, long *aValue) +{ + char *endptr; + *aValue = strtol(aArgs, &endptr, 0); + return (*endptr == '\0') ? OT_ERROR_NONE : OT_ERROR_PARSE; +} static void diag_output(const char *aFormat, ...) { @@ -48,15 +72,16 @@ void otPlatDiagSetOutputCallback(otInstance *aInstance, otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { - ARG_UNUSED(aInstance); - ARG_UNUSED(aArgsLength); - #if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) if (strcmp(aArgs[0], "modcarrier") == 0) { return startModCarrier(aInstance, aArgsLength - 1, aArgs + 1); } #endif + if (strcmp(aArgs[0], "transmit") == 0) { + return processTransmit(aInstance, aArgsLength - 1, aArgs + 1); + } + /* Add more platform specific diagnostics features here. */ diag_output("diag feature '%s' is not supported\r\n", aArgs[0]); @@ -80,6 +105,7 @@ bool otPlatDiagModeGet(void) void otPlatDiagChannelSet(uint8_t aChannel) { ARG_UNUSED(aChannel); + sChannel = aChannel; } void otPlatDiagTxPowerSet(int8_t aTxPower) @@ -99,19 +125,21 @@ void otPlatDiagRadioReceived(otInstance *aInstance, #if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable) { - if (!otPlatDiagModeGet()) { + if (!otPlatDiagModeGet() || (sTransmitMode != DIAG_TRANSMIT_MODE_IDLE && + sTransmitMode != DIAG_TRANSMIT_MODE_CARRIER)) { return OT_ERROR_INVALID_STATE; } + if (aEnable) { + sTransmitMode = DIAG_TRANSMIT_MODE_CARRIER; + } else { + sTransmitMode = DIAG_TRANSMIT_MODE_IDLE; + } + return platformRadioTransmitCarrier(aInstance, aEnable); } #endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */ -void otPlatDiagAlarmCallback(otInstance *aInstance) -{ - ARG_UNUSED(aInstance); -} - /* * To enable gpio diag commands, in Devicetree create `openthread` node in `/options/` path * with `compatible = "openthread,config"` property and `diag-gpios` property, @@ -291,9 +319,6 @@ otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { - ARG_UNUSED(aInstance); - ARG_UNUSED(aArgsLength); - bool enable = true; uint8_t data[OT_RADIO_FRAME_MAX_SIZE + 1]; @@ -301,15 +326,147 @@ static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char return OT_ERROR_INVALID_ARGS; } + if (!otPlatDiagModeGet() || (sTransmitMode != DIAG_TRANSMIT_MODE_IDLE && + sTransmitMode != DIAG_TRANSMIT_MODE_MODCARRIER)) { + return OT_ERROR_INVALID_STATE; + } + if (strcmp(aArgs[0], "stop") == 0) { enable = false; + sTransmitMode = DIAG_TRANSMIT_MODE_IDLE; } else { if (hex2bin(aArgs[0], strlen(aArgs[0]), data, ARRAY_SIZE(data)) == 0) { return OT_ERROR_INVALID_ARGS; } + sTransmitMode = DIAG_TRANSMIT_MODE_MODCARRIER; } return platformRadioTransmitModulatedCarrier(aInstance, enable, data); } #endif + +void otPlatDiagAlarmCallback(otInstance *aInstance) +{ + uint32_t now; + otRadioFrame *txPacket; + const uint16_t diag_packet_len = 30; + + if (sTransmitMode == DIAG_TRANSMIT_MODE_PACKETS) { + if ((sTxCount > 0) || (sTxCount == -1)) { + txPacket = otPlatRadioGetTransmitBuffer(aInstance); + + txPacket->mInfo.mTxInfo.mTxDelayBaseTime = 0; + txPacket->mInfo.mTxInfo.mTxDelay = 0; + txPacket->mInfo.mTxInfo.mMaxCsmaBackoffs = 0; + txPacket->mInfo.mTxInfo.mMaxFrameRetries = 0; + txPacket->mInfo.mTxInfo.mRxChannelAfterTxDone = sChannel; + txPacket->mInfo.mTxInfo.mTxPower = OT_RADIO_POWER_INVALID; + txPacket->mInfo.mTxInfo.mIsHeaderUpdated = false; + txPacket->mInfo.mTxInfo.mIsARetx = false; + txPacket->mInfo.mTxInfo.mCsmaCaEnabled = false; + txPacket->mInfo.mTxInfo.mCslPresent = false; + txPacket->mInfo.mTxInfo.mIsSecurityProcessed = false; + + txPacket->mLength = diag_packet_len; + + for (uint8_t i = 0; i < diag_packet_len; i++) { + txPacket->mPsdu[i] = i; + } + + otPlatRadioTransmit(aInstance, txPacket); + + if (sTxCount != -1) { + sTxCount--; + } + + now = otPlatAlarmMilliGetNow(); + otPlatAlarmMilliStartAt(aInstance, now, sTxPeriod); + } else { + sTransmitMode = DIAG_TRANSMIT_MODE_IDLE; + otPlatAlarmMilliStop(aInstance); + otPlatLog(OT_LOG_LEVEL_DEBG, OT_LOG_REGION_PLATFORM, "Transmit done"); + } + } +} + +static otError processTransmit(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) +{ + otError error = OT_ERROR_NONE; + long value; + uint32_t now; + + if (!otPlatDiagModeGet()) { + return OT_ERROR_INVALID_STATE; + } + + if (aArgsLength == 0) { + diag_output("transmit will send %" PRId32 " diagnostic messages with %" PRIu32 + " ms interval\r\n", + sTxRequestedCount, sTxPeriod); + + } else if (strcmp(aArgs[0], "stop") == 0) { + if (sTransmitMode == DIAG_TRANSMIT_MODE_IDLE) { + return OT_ERROR_INVALID_STATE; + } + + otPlatAlarmMilliStop(aInstance); + diag_output("diagnostic message transmission is stopped\r\n"); + sTransmitMode = DIAG_TRANSMIT_MODE_IDLE; + otPlatRadioReceive(aInstance, sChannel); + + } else if (strcmp(aArgs[0], "start") == 0) { + if (sTransmitMode != DIAG_TRANSMIT_MODE_IDLE) { + return OT_ERROR_INVALID_STATE; + } + + otPlatAlarmMilliStop(aInstance); + sTransmitMode = DIAG_TRANSMIT_MODE_PACKETS; + sTxCount = sTxRequestedCount; + now = otPlatAlarmMilliGetNow(); + otPlatAlarmMilliStartAt(aInstance, now, sTxPeriod); + diag_output("sending %" PRId32 " diagnostic messages with %" PRIu32 + " ms interval\r\n", + sTxRequestedCount, sTxPeriod); + } else if (strcmp(aArgs[0], "interval") == 0) { + + if (aArgsLength != 2) { + return OT_ERROR_INVALID_ARGS; + } + + error = parse_long(aArgs[1], &value); + if (error != OT_ERROR_NONE) { + return error; + } + + if (value <= 0) { + return OT_ERROR_INVALID_ARGS; + } + sTxPeriod = (uint32_t)(value); + diag_output("set diagnostic messages interval to %" PRIu32 + " ms\r\n", sTxPeriod); + + } else if (strcmp(aArgs[0], "count") == 0) { + + if (aArgsLength != 2) { + return OT_ERROR_INVALID_ARGS; + } + + error = parse_long(aArgs[1], &value); + if (error != OT_ERROR_NONE) { + return error; + } + + if ((value <= 0) && (value != -1)) { + return OT_ERROR_INVALID_ARGS; + } + + sTxRequestedCount = (uint32_t)(value); + diag_output("set diagnostic messages count to %" PRId32 "\r\n", + sTxRequestedCount); + } else { + return OT_ERROR_INVALID_ARGS; + } + + return error; +} diff --git a/west.yml b/west.yml index 6061b2c5a05..b99c5d1212d 100644 --- a/west.yml +++ b/west.yml @@ -300,7 +300,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 3cfca0192ff84da919e9bc7978bcc2239cd6a395 + revision: fbc6e614686b69dfa56f9694350b9488cf83d3f7 path: modules/bsim_hw_models/nrf_hw_models - name: nrf_wifi revision: f6b950a3b5c0187fe499b0e518426d5bf88b7e68