From 70add85f9f04dbfdba814f397d764b7cfe0d8cee Mon Sep 17 00:00:00 2001 From: Jamel Arbi Date: Tue, 16 Jul 2024 10:57:22 +0200 Subject: [PATCH] drivers: openthread: nxp: Add a HDLC RCP communication Add a HDLC RCP communication with its hdlc_api interface APIs and a NXP driver. Signed-off-by: Jamel Arbi --- drivers/CMakeLists.txt | 1 + drivers/Kconfig | 1 + drivers/hdlc_rcp_if/CMakeLists.txt | 5 + drivers/hdlc_rcp_if/Kconfig | 29 ++++ drivers/hdlc_rcp_if/Kconfig.nxp | 13 ++ drivers/hdlc_rcp_if/hdlc_rcp_if_nxp.c | 136 ++++++++++++++++++ dts/arm/nxp/nxp_rw6xx_common.dtsi | 9 ++ dts/bindings/hdlc_rcp_if/nxp,hdlc-rcp-if.yaml | 8 ++ include/zephyr/net/hdlc_rcp_if/hdlc_rcp_if.h | 77 ++++++++++ soc/nxp/rw/soc.h | 4 +- subsys/net/l2/openthread/openthread.c | 9 +- 11 files changed, 287 insertions(+), 5 deletions(-) create mode 100644 drivers/hdlc_rcp_if/CMakeLists.txt create mode 100644 drivers/hdlc_rcp_if/Kconfig create mode 100644 drivers/hdlc_rcp_if/Kconfig.nxp create mode 100644 drivers/hdlc_rcp_if/hdlc_rcp_if_nxp.c create mode 100644 dts/bindings/hdlc_rcp_if/nxp,hdlc-rcp-if.yaml create mode 100644 include/zephyr/net/hdlc_rcp_if/hdlc_rcp_if.h diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 05be8c3fd01..2536e201171 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -45,6 +45,7 @@ add_subdirectory_ifdef(CONFIG_FUEL_GAUGE fuel_gauge) add_subdirectory_ifdef(CONFIG_GNSS gnss) add_subdirectory_ifdef(CONFIG_GPIO gpio) add_subdirectory_ifdef(CONFIG_HAPTICS haptics) +add_subdirectory_ifdef(CONFIG_HDLC_RCP_IF hdlc_rcp_if) add_subdirectory_ifdef(CONFIG_HWINFO hwinfo) add_subdirectory_ifdef(CONFIG_HWSPINLOCK hwspinlock) add_subdirectory_ifdef(CONFIG_I2C i2c) diff --git a/drivers/Kconfig b/drivers/Kconfig index db80ba39a66..65f097f2acc 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -38,6 +38,7 @@ source "drivers/fuel_gauge/Kconfig" source "drivers/gnss/Kconfig" source "drivers/gpio/Kconfig" source "drivers/haptics/Kconfig" +source "drivers/hdlc_rcp_if/Kconfig" source "drivers/hwinfo/Kconfig" source "drivers/hwspinlock/Kconfig" source "drivers/i2c/Kconfig" diff --git a/drivers/hdlc_rcp_if/CMakeLists.txt b/drivers/hdlc_rcp_if/CMakeLists.txt new file mode 100644 index 00000000000..abae0200ad9 --- /dev/null +++ b/drivers/hdlc_rcp_if/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_HDLC_RCP_IF_NXP hdlc_rcp_if_nxp.c) diff --git a/drivers/hdlc_rcp_if/Kconfig b/drivers/hdlc_rcp_if/Kconfig new file mode 100644 index 00000000000..c2b77cd42a6 --- /dev/null +++ b/drivers/hdlc_rcp_if/Kconfig @@ -0,0 +1,29 @@ +# Configuration options for HDLC RCP communication Interface + +# Copyright (c) 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +# +# HDLC communication Interface used by Zephyr running Openthread RCP host +# + +menuconfig HDLC_RCP_IF + bool "HDLC interface for a Zephyr Openthread RCP host" + depends on NET_L2_OPENTHREAD && !OPENTHREAD_COPROCESSOR + +if HDLC_RCP_IF + +source "drivers/hdlc_rcp_if/Kconfig.nxp" + +config HDLC_RCP_IF_DRV_NAME + string "HDLC RCP Interface Driver's name" + default "hdlc_rcp_if" + help + This option sets the driver name + +module = HDLC_RCP_IF_DRIVER +module-str = HDLC driver for Openthread RCP host +module-help = Sets log level for Openthread HDLC RCP host interface Device Drivers. +source "subsys/logging/Kconfig.template.log_config" + +endif # HDLC_RCP_IF diff --git a/drivers/hdlc_rcp_if/Kconfig.nxp b/drivers/hdlc_rcp_if/Kconfig.nxp new file mode 100644 index 00000000000..743f422ba23 --- /dev/null +++ b/drivers/hdlc_rcp_if/Kconfig.nxp @@ -0,0 +1,13 @@ +# Configuration options for NXP HDLC RCP communication Interface + +# Copyright (c) 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +# +# HDLC communication Interface used by Zephyr running Openthread RCP host +# + +config HDLC_RCP_IF_NXP + bool "NXP HDLC interface for Zephyr Openthread RCP host" + default y + depends on DT_HAS_NXP_HDLC_RCP_IF_ENABLED diff --git a/drivers/hdlc_rcp_if/hdlc_rcp_if_nxp.c b/drivers/hdlc_rcp_if/hdlc_rcp_if_nxp.c new file mode 100644 index 00000000000..fb81b203377 --- /dev/null +++ b/drivers/hdlc_rcp_if/hdlc_rcp_if_nxp.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * IEEE 802.15.4 HDLC RCP interface. This is meant for network connectivity + * between a host and a RCP radio device. + */ + +/* -------------------------------------------------------------------------- */ +/* Includes */ +/* -------------------------------------------------------------------------- */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* -------------------------------------------------------------------------- */ +/* Definitions */ +/* -------------------------------------------------------------------------- */ + +#define DT_DRV_COMPAT nxp_hdlc_rcp_if + +#define LOG_MODULE_NAME hdlc_rcp_if_nxp +#define LOG_LEVEL CONFIG_HDLC_RCP_IF_DRIVER_LOG_LEVEL +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#define HDLC_RCP_IF_IRQ_N DT_INST_IRQ_BY_NAME(0, hdlc_rcp_if_int, irq) +#define HDLC_RCP_IF_IRQ_P DT_INST_IRQ_BY_NAME(0, hdlc_rcp_if_int, priority) +#define HDLC_RCP_IF_WAKEUP_IRQ_N DT_INST_IRQ_BY_NAME(0, wakeup_int, irq) +#define HDLC_RCP_IF_WAKEUP_IRQ_P DT_INST_IRQ_BY_NAME(0, wakeup_int, priority) + +struct ot_hdlc_rcp_context { + struct net_if *iface; + struct openthread_context *ot_context; +}; + +/* -------------------------------------------------------------------------- */ +/* Private prototypes */ +/* -------------------------------------------------------------------------- */ +extern int32_t hdlc_rcp_if_handler(void); +extern int32_t hdlc_rcp_if_wakeup_done_handler(void); + +/* -------------------------------------------------------------------------- */ +/* Private functions */ +/* -------------------------------------------------------------------------- */ + +static void hdlc_iface_init(struct net_if *iface) +{ + struct ot_hdlc_rcp_context *ctx = net_if_get_device(iface)->data; + otExtAddress eui64; + + /* HDLC RCP interface Interrupt */ + IRQ_CONNECT(HDLC_RCP_IF_IRQ_N, HDLC_RCP_IF_IRQ_P, hdlc_rcp_if_handler, 0, 0); + irq_enable(HDLC_RCP_IF_IRQ_N); + + /* Wake up done interrupt */ + IRQ_CONNECT(HDLC_RCP_IF_WAKEUP_IRQ_N, HDLC_RCP_IF_WAKEUP_IRQ_P, + hdlc_rcp_if_wakeup_done_handler, 0, 0); + irq_enable(HDLC_RCP_IF_WAKEUP_IRQ_N); + + ctx->iface = iface; + + ieee802154_init(iface); + + ctx->ot_context = net_if_l2_data(iface); + + otPlatRadioGetIeeeEui64(ctx->ot_context->instance, eui64.m8); + net_if_set_link_addr(iface, eui64.m8, OT_EXT_ADDRESS_SIZE, NET_LINK_IEEE802154); +} + +static int hdlc_register_rx_cb(hdlc_rx_callback_t hdlc_rx_callback, void *param) +{ + int ret = 0; + + ret = PLATFORM_InitHdlcInterface(hdlc_rx_callback, param); + if (ret < 0) { + LOG_ERR("HDLC RX callback registration failed"); + } + + return ret; +} + +static int hdlc_send(const uint8_t *frame, uint16_t length) +{ + int ret = 0; + + ret = PLATFORM_SendHdlcMessage((uint8_t *)frame, length); + if (ret < 0) { + LOG_ERR("HDLC send frame failed"); + } + + return ret; +} + +static int hdlc_deinit(void) +{ + int ret = 0; + + ret = PLATFORM_TerminateHdlcInterface(); + if (ret < 0) { + LOG_ERR("Failed to shutdown OpenThread controller"); + } + + return ret; +} + +static const struct hdlc_api nxp_hdlc_api = { + .iface_api.init = hdlc_iface_init, + .register_rx_cb = hdlc_register_rx_cb, + .send = hdlc_send, + .deinit = hdlc_deinit, +}; + +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(OPENTHREAD_L2) + +#define MTU 1280 + +NET_DEVICE_DT_INST_DEFINE(0, NULL, /* Initialization Function */ + NULL, /* No PM API support */ + NULL, /* No context data */ + NULL, /* Configuration info */ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, /* Initial priority */ + &nxp_hdlc_api, /* API interface functions */ + OPENTHREAD_L2, /* Openthread L2 */ + NET_L2_GET_CTX_TYPE(OPENTHREAD_L2), /* Openthread L2 context type */ + MTU); /* MTU size */ diff --git a/dts/arm/nxp/nxp_rw6xx_common.dtsi b/dts/arm/nxp/nxp_rw6xx_common.dtsi index b0e1e3781ac..2d436173c4d 100644 --- a/dts/arm/nxp/nxp_rw6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rw6xx_common.dtsi @@ -17,6 +17,7 @@ chosen { zephyr,entropy = &trng; zephyr,bt-hci = &hci; + zephyr,hdlc-rcp-if = &hdlc_rcp_if; }; cpus { @@ -521,6 +522,14 @@ interrupt-names = "hci_int", "wakeup_int"; }; + hdlc_rcp_if: hdlc_rcp_if { + compatible = "nxp,hdlc-rcp-if"; + /* first index is the hdlc_rcp_if interrupt */ + /* the second is the wake up done interrupt */ + interrupts = <90 2>, <82 2>; + interrupt-names = "hdlc_rcp_if_int", "wakeup_int"; + }; + enet: enet@138000 { compatible = "nxp,enet"; reg = <0x138000 0x700>; diff --git a/dts/bindings/hdlc_rcp_if/nxp,hdlc-rcp-if.yaml b/dts/bindings/hdlc_rcp_if/nxp,hdlc-rcp-if.yaml new file mode 100644 index 00000000000..226368063af --- /dev/null +++ b/dts/bindings/hdlc_rcp_if/nxp,hdlc-rcp-if.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP HDLC RCP interface node + +compatible: "nxp,hdlc-rcp-if" + +include: base.yaml diff --git a/include/zephyr/net/hdlc_rcp_if/hdlc_rcp_if.h b/include/zephyr/net/hdlc_rcp_if/hdlc_rcp_if.h new file mode 100644 index 00000000000..d26bf12bacc --- /dev/null +++ b/include/zephyr/net/hdlc_rcp_if/hdlc_rcp_if.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs of HDLC RCP communication Interface + * + * This file provide the HDLC APIs to be used by an RCP host + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief OT RCP HDLC RX callback function. + * + * @note This function is called in the radio spinel HDLC level + */ +typedef void (*hdlc_rx_callback_t)(uint8_t *data, uint16_t len, void *param); + +/** HDLC interface configuration data. */ +struct hdlc_api { + /** + * @brief HDLC interface API + */ + struct net_if_api iface_api; + + /** + * @brief Register the Spinel HDLC RX callback. + * + * @param hdlc_rx_callback pointer to the spinel HDLC RX callback + * @param param pointer to the spinel HDLC interface + * + * @retval 0 The callback was successfully registered. + * @retval -EIO The callback could not be registered. + */ + int (*register_rx_cb)(hdlc_rx_callback_t hdlc_rx_callback, void *param); + + /** + * @brief Transmit a HDLC frame + * + * + * @param frame pointer to the HDLC frame to be transmitted. + * @param length length of the HDLC frame to be transmitted. + + * @retval 0 The frame was successfully sent. + * @retval -EIO The frame could not be sent due to some unspecified + * interface error (e.g. the interface being busy). + */ + int (*send)(const uint8_t *frame, uint16_t length); + + /** + * @brief Deinitialize the device. + * + * @param none + * + * @retval 0 The interface was successfully stopped. + * @retval -EIO The interface could not be stopped. + */ + int (*deinit)(void); +}; + +/* Make sure that the interface API is properly setup inside + * HDLC interface API struct (it is the first one). + */ +BUILD_ASSERT(offsetof(struct hdlc_api, iface_api) == 0); + +#ifdef __cplusplus +} +#endif diff --git a/soc/nxp/rw/soc.h b/soc/nxp/rw/soc.h index 13f451493e9..1e29e78cd53 100644 --- a/soc/nxp/rw/soc.h +++ b/soc/nxp/rw/soc.h @@ -19,6 +19,9 @@ #define ble_hci_handler BLE_MCI_WAKEUP0_DriverIRQHandler #define ble_wakeup_done_handler BLE_MCI_WAKEUP_DONE0_DriverIRQHandler +#define hdlc_rcp_if_handler BLE_MCI_WAKEUP0_DriverIRQHandler +#define hdlc_rcp_if_wakeup_done_handler BLE_MCI_WAKEUP_DONE0_DriverIRQHandler + /* Wrapper Function to deal with SDK differences in power API */ static inline void EnableDeepSleepIRQ(IRQn_Type irq) { @@ -29,5 +32,4 @@ static inline void EnableDeepSleepIRQ(IRQn_Type irq) int flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate); #endif - #endif /* _SOC__H_ */ diff --git a/subsys/net/l2/openthread/openthread.c b/subsys/net/l2/openthread/openthread.c index c70adc0714c..c70a7e5d4e2 100644 --- a/subsys/net/l2/openthread/openthread.c +++ b/subsys/net/l2/openthread/openthread.c @@ -101,7 +101,7 @@ LOG_MODULE_REGISTER(net_l2_openthread, CONFIG_OPENTHREAD_L2_LOG_LEVEL); #define OT_POLL_PERIOD 0 #endif -#define PACKAGE_NAME "Zephyr" +#define ZEPHYR_PACKAGE_NAME "Zephyr" #define PACKAGE_VERSION KERNEL_VERSION_STRING extern void platformShellInit(otInstance *aInstance); @@ -159,12 +159,14 @@ static int ncp_hdlc_send(const uint8_t *buf, uint16_t len) return len; } +#ifndef CONFIG_HDLC_RCP_IF void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64) { ARG_UNUSED(instance); memcpy(ieee_eui64, ll_addr->addr, ll_addr->len); } +#endif /* CONFIG_HDLC_RCP_IF */ void otTaskletsSignalPending(otInstance *instance) { @@ -451,9 +453,8 @@ int openthread_start(struct openthread_context *ot_context) /* No dataset - initiate network join procedure. */ NET_DBG("Starting OpenThread join procedure."); - error = otJoinerStart(ot_instance, OT_JOINER_PSKD, NULL, - PACKAGE_NAME, OT_PLATFORM_INFO, - PACKAGE_VERSION, NULL, + error = otJoinerStart(ot_instance, OT_JOINER_PSKD, NULL, ZEPHYR_PACKAGE_NAME, + OT_PLATFORM_INFO, PACKAGE_VERSION, NULL, &ot_joiner_start_handler, ot_context); if (error != OT_ERROR_NONE) {