nrf_wifi: Add nRF71 support
nRF7120 PDK support that uses IPC as comms b/w APP and Wi-Fi domains. Signed-off-by: Chaitanya Tata <Chaitanya.Tata@nordicsemi.no>
This commit is contained in:
parent
08cc15aed8
commit
3953bb9ce3
16 changed files with 979 additions and 17 deletions
|
@ -27,9 +27,11 @@ zephyr_library_sources_ifndef(CONFIG_NRF70_OFFLOADED_RAW_TX
|
|||
src/fmac_main.c
|
||||
)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_WIFI_PATCHES_BUILTIN
|
||||
src/fw_load.c
|
||||
)
|
||||
if(NOT CONFIG_NRF71_ON_IPC)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_WIFI_PATCHES_BUILTIN
|
||||
src/fw_load.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT CONFIG_NRF70_RADIO_TEST AND NOT CONFIG_NRF70_OFFLOADED_RAW_TX)
|
||||
zephyr_library_sources(
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# TODO: Use DTS generated Kconfig once the board support is added
|
||||
DT_COMPAT_NORDIC_WIFI71 := nordic,wifi71
|
||||
|
||||
menuconfig WIFI_NRF70
|
||||
bool "nRF70 driver"
|
||||
select NET_L2_WIFI_MGMT if NETWORKING
|
||||
|
@ -16,7 +19,8 @@ menuconfig WIFI_NRF70
|
|||
depends on \
|
||||
DT_HAS_NORDIC_NRF7002_SPI_ENABLED || DT_HAS_NORDIC_NRF7002_QSPI_ENABLED || \
|
||||
DT_HAS_NORDIC_NRF7001_SPI_ENABLED || DT_HAS_NORDIC_NRF7001_QSPI_ENABLED || \
|
||||
DT_HAS_NORDIC_NRF7000_SPI_ENABLED || DT_HAS_NORDIC_NRF7000_QSPI_ENABLED
|
||||
DT_HAS_NORDIC_NRF7000_SPI_ENABLED || DT_HAS_NORDIC_NRF7000_QSPI_ENABLED || \
|
||||
$(dt_compat_enabled,$(DT_COMPAT_NORDIC_WIFI71))
|
||||
help
|
||||
Nordic Wi-Fi Driver
|
||||
|
||||
|
@ -24,7 +28,7 @@ if WIFI_NRF70
|
|||
# Hidden symbols for internal use
|
||||
config WIFI_NRF7002
|
||||
bool
|
||||
default y if DT_HAS_NORDIC_NRF7002_SPI_ENABLED || DT_HAS_NORDIC_NRF7002_QSPI_ENABLED
|
||||
default y if DT_HAS_NORDIC_NRF7002_SPI_ENABLED || DT_HAS_NORDIC_NRF7002_QSPI_ENABLED || $(dt_compat_enabled,$(DT_COMPAT_NORDIC_WIFI71))
|
||||
|
||||
config WIFI_NRF7001
|
||||
bool
|
||||
|
@ -151,6 +155,7 @@ endchoice
|
|||
config NRF_WIFI_LOW_POWER
|
||||
bool "Low power mode in nRF Wi-Fi chipsets"
|
||||
depends on !NRF70_RADIO_TEST && !NRF70_AP_MODE
|
||||
depends on !NRF71_ON_IPC
|
||||
default y
|
||||
|
||||
config NRF70_TCP_IP_CHECKSUM_OFFLOAD
|
||||
|
@ -202,6 +207,7 @@ config NRF70_SR_COEX_RF_SWITCH
|
|||
|
||||
config NRF70_SR_COEX_SLEEP_CTRL_GPIO_CTRL
|
||||
bool "Configuration of GPIO control for coexistence"
|
||||
depends on !NRF71_ON_IPC
|
||||
default y
|
||||
|
||||
config NRF70_SR_COEX_SWCTRL1_OUTPUT
|
||||
|
|
|
@ -485,8 +485,12 @@ void reg_change_callbk_fn(void *vif_ctx,
|
|||
}
|
||||
#endif /* !CONFIG_NRF70_RADIO_TEST */
|
||||
|
||||
#ifdef CONFIG_NRF71_ON_IPC
|
||||
#define MAX_TX_PWR(label) DT_PROP(DT_NODELABEL(wifi), label) * 4
|
||||
#else
|
||||
/* DTS uses 1dBm as the unit for TX power, while the RPU uses 0.25dBm */
|
||||
#define MAX_TX_PWR(label) DT_PROP(DT_NODELABEL(nrf70), label) * 4
|
||||
#endif /* CONFIG_NRF71_ON_IPC */
|
||||
|
||||
void configure_tx_pwr_settings(struct nrf_wifi_tx_pwr_ctrl_params *tx_pwr_ctrl_params,
|
||||
struct nrf_wifi_tx_pwr_ceil_params *tx_pwr_ceil_params)
|
||||
|
|
|
@ -31,12 +31,13 @@ enum nrf_wifi_status nrf_wifi_fw_load(void *rpu_ctx)
|
|||
LOG_ERR("%s: nrf_wifi_fmac_fw_parse failed", __func__);
|
||||
return status;
|
||||
}
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
/* Load the FW patches to the RPU */
|
||||
status = nrf_wifi_fmac_fw_load(rpu_ctx, &fw_info);
|
||||
|
||||
if (status != NRF_WIFI_STATUS_SUCCESS) {
|
||||
LOG_ERR("%s: nrf_wifi_fmac_fw_load failed", __func__);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -575,6 +575,7 @@ enum nrf_wifi_status nrf_wifi_get_mac_addr(struct nrf_wifi_vif_ctx_zep *vif_ctx_
|
|||
random_mac_addr,
|
||||
WIFI_MAC_ADDR_LEN);
|
||||
#elif CONFIG_WIFI_OTP_MAC_ADDRESS
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
status = nrf_wifi_fmac_otp_mac_addr_get(fmac_dev_ctx,
|
||||
vif_ctx_zep->vif_idx,
|
||||
vif_ctx_zep->mac_addr.addr);
|
||||
|
@ -583,6 +584,15 @@ enum nrf_wifi_status nrf_wifi_get_mac_addr(struct nrf_wifi_vif_ctx_zep *vif_ctx_
|
|||
__func__);
|
||||
goto unlock;
|
||||
}
|
||||
#else
|
||||
/* Set dummy MAC address */
|
||||
vif_ctx_zep->mac_addr.addr[0] = 0x00;
|
||||
vif_ctx_zep->mac_addr.addr[1] = 0x00;
|
||||
vif_ctx_zep->mac_addr.addr[2] = 0x5E;
|
||||
vif_ctx_zep->mac_addr.addr[3] = 0x00;
|
||||
vif_ctx_zep->mac_addr.addr[4] = 0x10;
|
||||
vif_ctx_zep->mac_addr.addr[5] = 0x00;
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
#endif
|
||||
|
||||
if (!nrf_wifi_utils_is_mac_addr_valid(vif_ctx_zep->mac_addr.addr)) {
|
||||
|
|
|
@ -26,8 +26,18 @@ if (CONFIG_NRF70_BUSLIB)
|
|||
inc
|
||||
${NRF_WIFI_DIR}/os_if/inc
|
||||
)
|
||||
zephyr_library_include_directories_ifdef(CONFIG_NRF71_ON_IPC
|
||||
${NRF_WIFI_DIR}/bus_if/bal/inc
|
||||
# QSPI is common to (Q)SPI and IPC
|
||||
${NRF_WIFI_DIR}/bus_if/bus/qspi/inc
|
||||
${NRF_WIFI_DIR}/fw_if/umac_if/inc/fw
|
||||
${NRF_WIFI_DIR}/hw_if/hal/inc
|
||||
)
|
||||
|
||||
zephyr_library_compile_definitions_ifdef(CONFIG_NRF71_ON_IPC
|
||||
NRF71_ON_IPC
|
||||
)
|
||||
zephyr_library_sources(
|
||||
rpu_hw_if.c
|
||||
device.c
|
||||
)
|
||||
if(NOT CONFIG_WIFI_NRF70)
|
||||
|
@ -36,9 +46,16 @@ if (CONFIG_NRF70_BUSLIB)
|
|||
)
|
||||
endif()
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF70_ON_QSPI
|
||||
rpu_hw_if.c
|
||||
qspi_if.c
|
||||
)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF70_ON_SPI
|
||||
rpu_hw_if.c
|
||||
spi_if.c
|
||||
)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF71_ON_IPC
|
||||
ipc_if.c
|
||||
ipc_service.c
|
||||
spsc_qm.c
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -10,6 +10,7 @@ DT_COMPAT_NORDIC_NRF7001_QSPI := nordic,nrf7001-qspi
|
|||
DT_COMPAT_NORDIC_NRF7001_SPI := nordic,nrf7001-spi
|
||||
DT_COMPAT_NORDIC_NRF7000_QSPI := nordic,nrf7000-qspi
|
||||
DT_COMPAT_NORDIC_NRF7000_SPI := nordic,nrf7000-spi
|
||||
DT_COMPAT_NORDIC_WIFI71 := nordic,wifi71
|
||||
|
||||
menuconfig NRF70_BUSLIB
|
||||
bool "NRF70 Bus Library"
|
||||
|
@ -30,6 +31,15 @@ config NRF70_ON_SPI
|
|||
$(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF7000_SPI))
|
||||
select SPI
|
||||
|
||||
config NRF71_ON_IPC
|
||||
def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_WIFI71))
|
||||
select MBOX
|
||||
select IPC_SERVICE
|
||||
select SPSC_PBUF
|
||||
help
|
||||
nRF71 is a Wi-Fi and BLE combo SoC and uses IPC as a communication
|
||||
between APP and Wi-Fi cores.
|
||||
|
||||
module = WIFI_NRF70_BUSLIB
|
||||
module-dep = LOG
|
||||
module-str = Log level for Wi-Fi nRF70 bus library
|
||||
|
|
|
@ -12,15 +12,26 @@
|
|||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/wifi/nrf_wifi/bus/qspi_if.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(CONFIG_NRF71_ON_IPC)
|
||||
#include "ipc_if.h"
|
||||
#else
|
||||
#include <zephyr/drivers/wifi/nrf_wifi/bus/qspi_if.h>
|
||||
#include "spi_if.h"
|
||||
|
||||
static struct qspi_config config;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NRF70_ON_QSPI)
|
||||
#if defined(CONFIG_NRF71_ON_IPC)
|
||||
static struct rpu_dev ipc = {
|
||||
.init = ipc_init,
|
||||
.deinit = ipc_deinit,
|
||||
.send = ipc_send,
|
||||
.recv = ipc_recv,
|
||||
.register_rx_cb = ipc_register_rx_cb,
|
||||
};
|
||||
#elif defined(CONFIG_NRF70_ON_QSPI)
|
||||
static struct qspi_dev qspi = {.init = qspi_init,
|
||||
.deinit = qspi_deinit,
|
||||
.read = qspi_read,
|
||||
|
@ -34,6 +45,7 @@ static struct qspi_dev spim = {.init = spim_init,
|
|||
.hl_read = spim_hl_read};
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
struct qspi_config *qspi_defconfig(void)
|
||||
{
|
||||
memset(&config, 0, sizeof(struct qspi_config));
|
||||
|
@ -71,12 +83,20 @@ struct qspi_config *qspi_get_config(void)
|
|||
{
|
||||
return &config;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
struct qspi_dev *qspi_dev(void)
|
||||
{
|
||||
#if CONFIG_NRF70_ON_QSPI
|
||||
#if defined(CONFIG_NRF70_ON_QSPI)
|
||||
return &qspi;
|
||||
#else
|
||||
return &spim;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
struct rpu_dev *rpu_dev(void)
|
||||
{
|
||||
return &ipc;
|
||||
}
|
||||
#endif /*! CONFIG_NRF71_ON_IPC */
|
||||
|
|
135
modules/nrf_wifi/bus/ipc_if.c
Normal file
135
modules/nrf_wifi/bus/ipc_if.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief File containing API definitions for the
|
||||
* IPC bus layer of the nRF71 Wi-Fi driver.
|
||||
*/
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(wifi_nrf_bus, CONFIG_WIFI_NRF70_BUSLIB_LOG_LEVEL);
|
||||
|
||||
#include "ipc_if.h"
|
||||
#include "bal_structs.h"
|
||||
#include "qspi.h"
|
||||
#include "common/hal_structs_common.h"
|
||||
|
||||
/* Define addresses to use for the free queues */
|
||||
#define EVENT_FREEQ_ADDR 0x200C2000
|
||||
#define CMD_FREEQ_ADDR 0x200C3000
|
||||
|
||||
#define NUM_INSTANCES 3
|
||||
#define NUM_ENDPOINTS 1
|
||||
|
||||
struct device *ipc_instances[NUM_INSTANCES];
|
||||
struct ipc_ept ept[NUM_ENDPOINTS];
|
||||
struct ipc_ept_cfg ept_cfg[NUM_ENDPOINTS];
|
||||
|
||||
static wifi_ipc_t wifi_event;
|
||||
static wifi_ipc_t wifi_cmd;
|
||||
static wifi_ipc_t wifi_tx;
|
||||
|
||||
static int (*callback_func)(void *data);
|
||||
|
||||
static void event_recv(void *data, void *priv)
|
||||
{
|
||||
struct nrf_wifi_bus_qspi_dev_ctx *dev_ctx = NULL;
|
||||
struct nrf_wifi_bal_dev_ctx *bal_dev_ctx = NULL;
|
||||
struct nrf_wifi_hal_dev_ctx *hal_dev_ctx = NULL;
|
||||
|
||||
dev_ctx = (struct nrf_wifi_bus_qspi_dev_ctx *)priv;
|
||||
bal_dev_ctx = (struct nrf_wifi_bal_dev_ctx *)dev_ctx->bal_dev_ctx;
|
||||
hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)bal_dev_ctx->hal_dev_ctx;
|
||||
LOG_DBG("Event IPC received");
|
||||
|
||||
hal_dev_ctx->ipc_msg = data;
|
||||
callback_func(priv);
|
||||
LOG_DBG("Event IPC callback completed");
|
||||
}
|
||||
|
||||
int ipc_init(void)
|
||||
{
|
||||
wifi_ipc_host_event_init(&wifi_event, EVENT_FREEQ_ADDR);
|
||||
LOG_DBG("Event IPC initialized");
|
||||
wifi_ipc_host_cmd_init(&wifi_cmd, CMD_FREEQ_ADDR);
|
||||
LOG_DBG("Command IPC initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_deinit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_recv(ipc_ctx_t ctx, void *data, int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_send(ipc_ctx_t ctx, const void *data, int len)
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
|
||||
switch (ctx.inst) {
|
||||
case IPC_INSTANCE_CMD_CTRL:
|
||||
/* IPC service on RPU may not have been established. Keep trying. */
|
||||
do {
|
||||
ret = wifi_ipc_host_cmd_send_memcpy(&wifi_cmd, data, len);
|
||||
} while (ret == WIFI_IPC_STATUS_BUSYQ_NOTREADY);
|
||||
|
||||
/* Critical error during IPC service transfer. Should never happen. */
|
||||
if (ret == WIFI_IPC_STATUS_BUSYQ_CRITICAL_ERR) {
|
||||
LOG_ERR("Critical error during IPC CMD busyq transfer");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case IPC_INSTANCE_CMD_TX:
|
||||
/* IPC service on RPU may not have been established. Keep trying. */
|
||||
do {
|
||||
ret = wifi_ipc_host_tx_send(&wifi_tx, data);
|
||||
} while (ret == WIFI_IPC_STATUS_BUSYQ_NOTREADY);
|
||||
|
||||
/* Critical error during IPC service transfer. Should never happen. */
|
||||
if (ret == WIFI_IPC_STATUS_BUSYQ_CRITICAL_ERR) {
|
||||
LOG_ERR("Critical error during IPC TX busyq transfer");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case IPC_INSTANCE_RX:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_DBG("IPC send completed: %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ipc_register_rx_cb(int (*rx_handler)(void *priv), void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
callback_func = rx_handler;
|
||||
|
||||
ret = wifi_ipc_bind_ipc_service_tx_rx(&wifi_cmd, &wifi_event,
|
||||
DEVICE_DT_GET(DT_NODELABEL(ipc0)), event_recv, data);
|
||||
if (ret != WIFI_IPC_STATUS_OK) {
|
||||
LOG_ERR("Failed to bind IPC service: %d", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = wifi_ipc_bind_ipc_service(&wifi_tx, DEVICE_DT_GET(DT_NODELABEL(ipc1)), event_recv,
|
||||
data);
|
||||
if (ret != WIFI_IPC_STATUS_OK) {
|
||||
LOG_ERR("Failed to bind IPC service: %d", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
48
modules/nrf_wifi/bus/ipc_if.h
Normal file
48
modules/nrf_wifi/bus/ipc_if.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __IPC_IF_H__
|
||||
#define __IPC_IF_H__
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include "ipc_service.h"
|
||||
|
||||
typedef enum {
|
||||
IPC_INSTANCE_CMD_CTRL = 0,
|
||||
IPC_INSTANCE_CMD_TX,
|
||||
IPC_INSTANCE_EVT,
|
||||
IPC_INSTANCE_RX
|
||||
} ipc_instances_nrf71_t;
|
||||
|
||||
typedef enum {
|
||||
IPC_EPT_UMAC = 0,
|
||||
IPC_EPT_LMAC
|
||||
} ipc_epts_nrf71_t;
|
||||
|
||||
typedef struct ipc_ctx {
|
||||
ipc_instances_nrf71_t inst;
|
||||
ipc_epts_nrf71_t ept;
|
||||
} ipc_ctx_t;
|
||||
|
||||
struct rpu_dev {
|
||||
int (*init)();
|
||||
int (*deinit)(void);
|
||||
int (*send)(ipc_ctx_t ctx, const void *data, int len);
|
||||
int (*recv)(ipc_ctx_t ctx, void *data, int len);
|
||||
int (*register_rx_cb)(int (*rx_handler)(void *priv), void *data);
|
||||
};
|
||||
|
||||
struct rpu_dev *rpu_dev(void);
|
||||
|
||||
int ipc_init(void);
|
||||
int ipc_deinit(void);
|
||||
int ipc_send(ipc_ctx_t ctx, const void *data, int len);
|
||||
/* Blocking Receive */
|
||||
int ipc_recv(ipc_ctx_t ctx, void *data, int len);
|
||||
/* Non-blocking Receive (global, not per instance) */
|
||||
int ipc_register_rx_cb(int (*rx_handler)(void *priv), void *data);
|
||||
|
||||
#endif /* __IPC_IF_H__ */
|
206
modules/nrf_wifi/bus/ipc_service.c
Normal file
206
modules/nrf_wifi/bus/ipc_service.c
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief File containing API definitions for the
|
||||
* IPC service layer of the nrf71 Wi-Fi driver.
|
||||
*/
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(wifi_nrf_bus, CONFIG_WIFI_NRF70_BUSLIB_LOG_LEVEL);
|
||||
|
||||
#include "ipc_service.h"
|
||||
|
||||
static void wifi_ipc_ep_bound(void *priv)
|
||||
{
|
||||
wifi_ipc_t *context = (wifi_ipc_t *)priv;
|
||||
|
||||
context->busy_q.ipc_ready = true;
|
||||
}
|
||||
|
||||
static void wifi_ipc_recv_callback(const void *data, size_t len, void *priv)
|
||||
{
|
||||
(void)len;
|
||||
uint32_t global_addr = *((uint32_t *)data);
|
||||
|
||||
wifi_ipc_t *context = (wifi_ipc_t *)priv;
|
||||
|
||||
context->busy_q.recv_cb((void *)global_addr, context->busy_q.priv);
|
||||
|
||||
if (context->free_q != NULL) {
|
||||
while (!spsc32_push(context->free_q, global_addr)) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_ipc_busyq_init(wifi_ipc_busyq_t *busyq, const ipc_device_wrapper_t *ipc_inst,
|
||||
void *rx_cb, void *priv)
|
||||
{
|
||||
busyq->ipc_inst = ipc_inst;
|
||||
busyq->ipc_ep_cfg.cb.bound = wifi_ipc_ep_bound;
|
||||
busyq->ipc_ep_cfg.cb.received = wifi_ipc_recv_callback;
|
||||
busyq->recv_cb = rx_cb;
|
||||
busyq->ipc_ready = false;
|
||||
busyq->priv = priv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the IPC service on the busy_queue
|
||||
*/
|
||||
static wifi_ipc_status_t wifi_ipc_busyq_register(wifi_ipc_t *context)
|
||||
{
|
||||
int ret;
|
||||
const struct device *ipc_instance = GET_IPC_INSTANCE(context->busy_q.ipc_inst);
|
||||
|
||||
ret = ipc_service_open_instance(ipc_instance);
|
||||
if (ret < 0) {
|
||||
return WIFI_IPC_STATUS_INIT_ERR;
|
||||
}
|
||||
|
||||
context->busy_q.ipc_ep_cfg.name = "ep";
|
||||
context->busy_q.ipc_ep_cfg.priv = context;
|
||||
|
||||
ret = ipc_service_register_endpoint(ipc_instance, &context->busy_q.ipc_ep,
|
||||
&context->busy_q.ipc_ep_cfg);
|
||||
if (ret < 0 && ret != -EALREADY) {
|
||||
return WIFI_IPC_STATUS_INIT_ERR;
|
||||
}
|
||||
|
||||
LOG_INF("IPC busy queue registered");
|
||||
|
||||
return WIFI_IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_bind_ipc_service(wifi_ipc_t *context,
|
||||
const ipc_device_wrapper_t *ipc_inst,
|
||||
void (*rx_cb)(void *data, void *priv), void *priv)
|
||||
{
|
||||
wifi_ipc_busyq_init(&context->busy_q, ipc_inst, rx_cb, priv);
|
||||
return wifi_ipc_busyq_register(context);
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_bind_ipc_service_tx_rx(wifi_ipc_t *tx, wifi_ipc_t *rx,
|
||||
const ipc_device_wrapper_t *ipc_inst,
|
||||
void (*rx_cb)(void *data, void *priv), void *priv)
|
||||
{
|
||||
wifi_ipc_busyq_init(&rx->busy_q, ipc_inst, rx_cb, priv);
|
||||
|
||||
/**
|
||||
* When initialising an IPC service, both TX and RX mailboxes need to be
|
||||
* registered at the same time using a single function call. Both tx and
|
||||
* rx need to refer to the same IPC instance.
|
||||
*/
|
||||
tx->linked_ipc = &rx->busy_q;
|
||||
|
||||
return wifi_ipc_busyq_register(rx);
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_freeq_get(wifi_ipc_t *context, uint32_t *data)
|
||||
{
|
||||
if (context->free_q == NULL) {
|
||||
LOG_ERR("Free queue is not initialised");
|
||||
return WIFI_IPC_STATUS_FREEQ_UNINIT_ERR;
|
||||
}
|
||||
|
||||
if (spsc32_is_empty(context->free_q)) {
|
||||
LOG_DBG("Free queue is empty");
|
||||
return WIFI_IPC_STATUS_FREEQ_EMPTY;
|
||||
}
|
||||
|
||||
if (!spsc32_read_head(context->free_q, data)) {
|
||||
LOG_DBG("Free queue is empty");
|
||||
return WIFI_IPC_STATUS_FREEQ_EMPTY;
|
||||
}
|
||||
|
||||
return WIFI_IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_freeq_send(wifi_ipc_t *context, uint32_t data)
|
||||
{
|
||||
return (spsc32_push(context->free_q, data) == true ? WIFI_IPC_STATUS_OK
|
||||
: WIFI_IPC_STATUS_FREEQ_FULL);
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_busyq_send(wifi_ipc_t *context, uint32_t *data)
|
||||
{
|
||||
/* Get correct linked endpoint */
|
||||
wifi_ipc_busyq_t *busyq =
|
||||
context->linked_ipc ? context->linked_ipc : &context->busy_q;
|
||||
|
||||
if (!busyq->ipc_ready) {
|
||||
LOG_ERR("IPC service is not ready");
|
||||
return WIFI_IPC_STATUS_BUSYQ_NOTREADY;
|
||||
}
|
||||
|
||||
int ret = ipc_service_send(&busyq->ipc_ep, data, sizeof(*data));
|
||||
|
||||
if (ret == -ENOMEM) {
|
||||
LOG_ERR("No space in the buffer");
|
||||
/* No space in the buffer */
|
||||
return WIFI_IPC_STATUS_BUSYQ_FULL;
|
||||
} else if (ret < 0) {
|
||||
LOG_ERR("Critical IPC failure: %d", ret);
|
||||
/* Critical IPC failure */
|
||||
return WIFI_IPC_STATUS_BUSYQ_CRITICAL_ERR;
|
||||
}
|
||||
|
||||
if (context->free_q != NULL) {
|
||||
/* Free up global address pointer from the free queue */
|
||||
uint32_t data_out;
|
||||
|
||||
return (spsc32_pop(context->free_q, &data_out) == true
|
||||
? (*data == data_out ? WIFI_IPC_STATUS_OK
|
||||
: WIFI_IPC_STATUS_FREEQ_INVALID)
|
||||
: WIFI_IPC_STATUS_FREEQ_EMPTY);
|
||||
}
|
||||
|
||||
return WIFI_IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_init(wifi_ipc_t *context, uint32_t addr_freeq)
|
||||
{
|
||||
context->free_q = (void *)addr_freeq;
|
||||
return WIFI_IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_host_event_init(wifi_ipc_t *context, uint32_t addr_freeq)
|
||||
{
|
||||
context->free_q = (void *)addr_freeq;
|
||||
return WIFI_IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_get(wifi_ipc_t *context, uint32_t *data)
|
||||
{
|
||||
return wifi_ipc_freeq_get(context, data);
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_send(wifi_ipc_t *context, uint32_t *data)
|
||||
{
|
||||
return wifi_ipc_busyq_send(context, data);
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_send_memcpy(wifi_ipc_t *context, const void *msg,
|
||||
size_t len)
|
||||
{
|
||||
int ret;
|
||||
uint32_t gdram_addr;
|
||||
|
||||
ret = wifi_ipc_host_cmd_get(context, &gdram_addr);
|
||||
if (ret != WIFI_IPC_STATUS_OK) {
|
||||
LOG_ERR("Failed to get command location from free queue: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy((void *)gdram_addr, msg, len);
|
||||
|
||||
return wifi_ipc_host_cmd_send(context, &gdram_addr);
|
||||
}
|
||||
|
||||
wifi_ipc_status_t wifi_ipc_host_tx_send(wifi_ipc_t *context, const void *msg)
|
||||
{
|
||||
return wifi_ipc_host_cmd_send(context, (uint32_t *)&msg);
|
||||
}
|
260
modules/nrf_wifi/bus/ipc_service.h
Normal file
260
modules/nrf_wifi/bus/ipc_service.h
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef IPC_SERVICE_H
|
||||
#define IPC_SERVICE_H
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/ipc/ipc_service.h>
|
||||
#include "spsc_qm.h"
|
||||
|
||||
#define GET_IPC_INSTANCE(dev) (dev)
|
||||
typedef struct device ipc_device_wrapper_t;
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* Must be large enough to contain the internal struct (spsc_pbuf struct) and
|
||||
* at least two bytes of data (one is reserved for written message length)
|
||||
*/
|
||||
#define _MIN_SPSC_SIZE (sizeof(spsc_queue_t) + sizeof(uint32_t))
|
||||
/*
|
||||
* TODO: Unsure why some additional bytes are needed for overhead.
|
||||
*/
|
||||
#define WIFI_IPC_GET_SPSC_SIZE(x) (_MIN_SPSC_SIZE + 12 + (x))
|
||||
|
||||
/* 4 x cmd location 32-bit pointers of 400 bytes each */
|
||||
#define WIFI_IPC_CMD_SIZE 400
|
||||
#define WIFI_IPC_CMD_NUM 4
|
||||
#define WIFI_IPC_CMD_SPSC_SIZE WIFI_IPC_GET_SPSC_SIZE(WIFI_IPC_CMD_NUM * sizeof(uint32_t))
|
||||
|
||||
/* 7 x event location 32-bit pointers of 1000 bytes each */
|
||||
#define WIFI_IPC_EVENT_SIZE 1000
|
||||
#define WIFI_IPC_EVENT_NUM 7
|
||||
#define WIFI_IPC_EVENT_SPSC_SIZE WIFI_IPC_GET_SPSC_SIZE(WIFI_IPC_EVENT_NUM * sizeof(uint32_t))
|
||||
|
||||
/**
|
||||
* @enum wifi_ipc_status_t
|
||||
* @brief Status codes for the Wi-Fi IPC service.
|
||||
*
|
||||
* This enumeration defines various status codes that represent
|
||||
* the state or result of operations in the Wi-Fi IPC service.
|
||||
*/
|
||||
typedef enum {
|
||||
/** Status indicating the operation completed successfully. */
|
||||
WIFI_IPC_STATUS_OK = 0,
|
||||
|
||||
/** Error indicating failure to register IPC service for the Busy queue. */
|
||||
WIFI_IPC_STATUS_INIT_ERR,
|
||||
|
||||
/** Error indicating that the Free queue has not been initialized. */
|
||||
WIFI_IPC_STATUS_FREEQ_UNINIT_ERR,
|
||||
|
||||
/** Status indicating that the Free queue is empty. */
|
||||
WIFI_IPC_STATUS_FREEQ_EMPTY,
|
||||
|
||||
/** Error indicating that the value passed to wifi_ipc_busyq_send()
|
||||
* does not match the value from the Free queue.
|
||||
*/
|
||||
WIFI_IPC_STATUS_FREEQ_INVALID,
|
||||
|
||||
/** Status indicating that the Free queue is full. */
|
||||
WIFI_IPC_STATUS_FREEQ_FULL,
|
||||
|
||||
/** Error indicating that the IPC service for the Busy queue connection
|
||||
* has not been established.
|
||||
*/
|
||||
WIFI_IPC_STATUS_BUSYQ_NOTREADY,
|
||||
|
||||
/** Status indicating that the Busy queue is full. */
|
||||
WIFI_IPC_STATUS_BUSYQ_FULL,
|
||||
|
||||
/** Critical error indicating an IPC transfer failure. This should never happen. */
|
||||
WIFI_IPC_STATUS_BUSYQ_CRITICAL_ERR,
|
||||
} wifi_ipc_status_t;
|
||||
|
||||
/**
|
||||
* Structure to hold context information for busy queue.
|
||||
*/
|
||||
typedef struct {
|
||||
const ipc_device_wrapper_t *ipc_inst;
|
||||
struct ipc_ept ipc_ep;
|
||||
struct ipc_ept_cfg ipc_ep_cfg;
|
||||
void (*recv_cb)(const void *data, const void *priv);
|
||||
const void *priv;
|
||||
volatile bool ipc_ready;
|
||||
} wifi_ipc_busyq_t;
|
||||
|
||||
/**
|
||||
* Top-level structure to hold context information for sending data between RPU
|
||||
* and the Host.
|
||||
*/
|
||||
typedef struct {
|
||||
spsc_queue_t *free_q;
|
||||
|
||||
wifi_ipc_busyq_t busy_q;
|
||||
wifi_ipc_busyq_t *linked_ipc;
|
||||
} wifi_ipc_t;
|
||||
|
||||
/**
|
||||
* Performs memory-to-memory copy via MVDMA.
|
||||
*
|
||||
* Enters low power state by issuing wait-for-interrupt (WFI) while waiting for
|
||||
* MVDMA event to complete.
|
||||
*
|
||||
* @param[in] p_dest : Pointer to destination memory to be copied to.
|
||||
* @param[in] p_src : Pointer to source memory to be copied from.
|
||||
* @param[in] len : Number of bytes to be copied.
|
||||
*/
|
||||
void wifi_ipc_mvdma_copy(void *p_dest, const void *p_src, size_t len);
|
||||
|
||||
/**
|
||||
* Bind either TX or RX context to one IPC service. This utilises the half-duplex
|
||||
* capability of the IPC service.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] ipc_inst : Pointer to the IPC instance.
|
||||
* @param[in] rx_cb : If binding RX context, this is the callback function.
|
||||
* Leave NULL if binding to a TX.
|
||||
* @param[in] priv : If binding RX context, this is the private data to be passed
|
||||
* along with the callback function.
|
||||
* Leave NULL if binding to a TX.
|
||||
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_init_err.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_bind_ipc_service(wifi_ipc_t *p_context,
|
||||
const ipc_device_wrapper_t *ipc_inst,
|
||||
void (*rx_cb)(void *data, void *priv), void *priv);
|
||||
|
||||
/**
|
||||
* Bind both TX and RX contexts to a single IPC service. This utilises the
|
||||
* full-duplex capability of the IPC service.
|
||||
*
|
||||
* @param[in] p_tx : Pointer to wifi_ipc_t struct to bind IPC TX mailbox to.
|
||||
* @param[in] p_rx : Pointer to wifi_ipc_t struct to bind IPC RX mailbox to.
|
||||
* @param[in] ipc_inst : Pointer to the IPC instance.
|
||||
* @param[in] rx_cb : Callback function to bind to data in received from RX mailbox.
|
||||
* @param[in] priv : Private data to the callback function.
|
||||
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_init_err.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_bind_ipc_service_tx_rx(wifi_ipc_t *p_tx, wifi_ipc_t *p_rx,
|
||||
const ipc_device_wrapper_t *ipc_inst,
|
||||
void (*rx_cb)(void *data, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* Get data from the free queue.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[out] data : Pointer to the data to read to.
|
||||
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_freeq_empty.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_freeq_get(wifi_ipc_t *p_context, uint32_t *data);
|
||||
|
||||
/**
|
||||
* Send data to the free queue.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] data : 32-bit data to send.
|
||||
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_freeq_full.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_freeq_send(wifi_ipc_t *p_context, uint32_t data);
|
||||
|
||||
/**
|
||||
* Send data to the busy queue over IPC service, and pop the same data from the
|
||||
* free queue.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] data : Pointer to the data to send to.
|
||||
* @return : wifi_ipc_status_ok if successful, otherwise one of the following:
|
||||
* - wifi_ipc_status_busyq_notready
|
||||
* - wifi_ipc_status_busyq_full
|
||||
* - wifi_ipc_status_busyq_critical_err
|
||||
* - wifi_ipc_status_freeq_invalid
|
||||
* - wifi_ipc_status_freeq_empty
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_busyq_send(wifi_ipc_t *p_context, uint32_t *data);
|
||||
|
||||
/**
|
||||
* Prepares and initialises the Host for sending a command to RPU.
|
||||
*
|
||||
* The free queue points to the already allocated free queue from the RPU.
|
||||
*
|
||||
* The busy queue using IPC service must be initialised using @see wifi_ipc_bind_ipc_service()
|
||||
* or @see wifi_ipc_bind_ipc_service_tx_rx().
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] addr_freeq : Address of the allocated free queue.
|
||||
* @return : wifi_ipc_status_ok if successful.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_init(wifi_ipc_t *p_context, uint32_t addr_freeq);
|
||||
|
||||
/**
|
||||
* Prepares and initialises the Host for receiving an event from RPU.
|
||||
*
|
||||
* The free queue points to the already allocated free queue from the RPU.
|
||||
*
|
||||
* The busy queue using IPC service must be initialised using @see wifi_ipc_bind_ipc_service()
|
||||
* or @see wifi_ipc_bind_ipc_service_tx_rx().
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] addr_freeq : Address of the allocated SPSC free queue.
|
||||
* @return : wifi_ipc_status_ok if successful.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_host_event_init(wifi_ipc_t *p_context, uint32_t addr_freeq);
|
||||
|
||||
/**
|
||||
* Get a command location from the free queue.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[out] p_data : Pointer to data to write event location to.
|
||||
* @return : wifi_ipc_status_ok if successful, otherwise wifi_ipc_status_freeq_empty.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_get(wifi_ipc_t *p_context, uint32_t *p_data);
|
||||
|
||||
/**
|
||||
* Send an event location pointer to the Host and frees up the event location
|
||||
* pointer from the free queue.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] p_data : Pointer to command location to be sent.
|
||||
* @return : wifi_ipc_status_ok if successful, otherwise one of the following
|
||||
* - wifi_ipc_status_busyq_notready
|
||||
* - wifi_ipc_status_busyq_full
|
||||
* - wifi_ipc_status_busyq_critical_err
|
||||
* - wifi_ipc_status_freeq_invalid
|
||||
* - wifi_ipc_status_freeq_empty
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_send(wifi_ipc_t *p_context, uint32_t *p_data);
|
||||
|
||||
/**
|
||||
* Send a command from the Host to RPU using standard memcpy.
|
||||
*
|
||||
* 1. Retrieves an address pointer of Packet RAM from the free queue.
|
||||
* 2. Copies local message to the retrieved address pointer via memcpy.
|
||||
* 3. Sends the address pointer to the busy queue via IPC service.
|
||||
* 4. Upon successful transmission, removes the address pointer the free queue.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] p_msg : Pointer the local message to be copied to Packet RAM via memcpy.
|
||||
* @param[in] len : Length of the local message in bytes.
|
||||
* @return : wifi_ipc_status_ok if send is successful, otherwise one of
|
||||
* status code from wifi_ipc_status_t will be returned.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_host_cmd_send_memcpy(wifi_ipc_t *p_context, const void *p_msg,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* Send a tx data pointer from the Host to RPU and raises RPU interrupt.
|
||||
*
|
||||
* @param[in] p_context : Pointer to wifi_ipc_t struct.
|
||||
* @param[in] p_msg : Pointer to message.
|
||||
* @return : wifi_ipc_status_ok if send is successful, otherwise one of
|
||||
* status code from wifi_ipc_status_t will be returned.
|
||||
*/
|
||||
wifi_ipc_status_t wifi_ipc_host_tx_send(wifi_ipc_t *p_context, const void *p_msg);
|
||||
|
||||
#endif /* IPC_SERVICE_H */
|
84
modules/nrf_wifi/bus/spsc_qm.c
Normal file
84
modules/nrf_wifi/bus/spsc_qm.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief File containing API definitions for the
|
||||
* SPSC queue management layer of the nRF71 Wi-Fi driver.
|
||||
*/
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(wifi_nrf_bus, CONFIG_WIFI_NRF70_BUSLIB_LOG_LEVEL);
|
||||
|
||||
#include "spsc_qm.h"
|
||||
|
||||
spsc_queue_t *spsc32_init(uint32_t address, size_t size)
|
||||
{
|
||||
return spsc_pbuf_init((void *)address, size, 0);
|
||||
}
|
||||
|
||||
bool spsc32_push(spsc_queue_t *queue, uint32_t value)
|
||||
{
|
||||
char *pbuf;
|
||||
uint8_t len = sizeof(uint32_t);
|
||||
|
||||
if (spsc_pbuf_alloc(queue, len, &pbuf) != len) {
|
||||
LOG_ERR("%s: Failed to allocate buffer", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(pbuf, &value, len);
|
||||
spsc_pbuf_commit(queue, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spsc32_pop(spsc_queue_t *queue, uint32_t *out_value)
|
||||
{
|
||||
char *buf;
|
||||
uint16_t plen = spsc_pbuf_claim(queue, &buf);
|
||||
|
||||
if (plen == 0) {
|
||||
LOG_ERR("%s: Failed to claim buffer", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
spsc_pbuf_free(queue, plen);
|
||||
|
||||
*out_value = *((uint32_t *)buf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spsc32_read_head(spsc_queue_t *queue, uint32_t *out_value)
|
||||
{
|
||||
char *buf;
|
||||
uint16_t plen = spsc_pbuf_claim(queue, &buf);
|
||||
|
||||
if (plen == 0) {
|
||||
LOG_ERR("%s: Failed to claim buffer", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_value = *((uint32_t *)buf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spsc32_is_empty(spsc_queue_t *queue)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
return spsc_pbuf_claim(queue, &buf) == 0;
|
||||
}
|
||||
|
||||
bool spsc32_is_full(spsc_queue_t *queue)
|
||||
{
|
||||
char *pbuf;
|
||||
uint8_t len = sizeof(uint32_t);
|
||||
|
||||
return spsc_pbuf_alloc(queue, len, &pbuf) != len;
|
||||
}
|
79
modules/nrf_wifi/bus/spsc_qm.h
Normal file
79
modules/nrf_wifi/bus/spsc_qm.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief File containing API definitions for the
|
||||
* SPSC queue management layer of the nRF71 Wi-Fi driver.
|
||||
|
||||
* SPSC Queue Manager API for handling 32-bit values.
|
||||
*
|
||||
* The Queue Manager API for Single-Producer, Single-Consumer (SPSC) queue. This
|
||||
* API allows queues to be allocated, pushed and popped.
|
||||
*/
|
||||
|
||||
#ifndef SPSC_QM_H
|
||||
#define SPSC_QM_H
|
||||
|
||||
#include <zephyr/sys/spsc_pbuf.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct spsc_pbuf spsc_queue_t;
|
||||
|
||||
/**
|
||||
* Initialise and allocate SPSC queue.
|
||||
*
|
||||
* @param[in] address : Address to allocate.
|
||||
* @param[in] size : Size in bytes to allocate.
|
||||
* @return : SPSC packet queue.
|
||||
*/
|
||||
spsc_queue_t *spsc32_init(uint32_t address, size_t size);
|
||||
|
||||
/**
|
||||
* Push a value onto the tail of a queue.
|
||||
*
|
||||
* @param[in] pb : Pointer to SPSC packet queue.
|
||||
* @param[in] value : The value to push to the queue.
|
||||
* @return : true if push is successful, false otherwise.
|
||||
*/
|
||||
bool spsc32_push(spsc_queue_t *pb, uint32_t value);
|
||||
|
||||
/**
|
||||
* Pop a value from the head of a queue and return it.
|
||||
*
|
||||
* @param[in] pb : Pointer to SPSC packet queue.
|
||||
* @param[out] out_value : Pointer to the value to pop to.
|
||||
* @return : true if pop is successful, false otherwise.
|
||||
*/
|
||||
bool spsc32_pop(spsc_queue_t *pb, uint32_t *out_value);
|
||||
|
||||
/**
|
||||
* Return a value at the head of a queue without popping it.
|
||||
*
|
||||
* @param[in] pb : Pointer to SPSC packet queue.
|
||||
* @param[out] out_value : Pointer to value to read from the head of the queue.
|
||||
* @return : true if read is successful, false otherwise.
|
||||
*/
|
||||
bool spsc32_read_head(spsc_queue_t *pb, uint32_t *out_value);
|
||||
|
||||
/**
|
||||
* Test whether a queue is empty.
|
||||
*
|
||||
* @param[in] pb : Pointer to SPSC packet queue.
|
||||
* @return : true if the queue is empty, false otherwise.
|
||||
*/
|
||||
bool spsc32_is_empty(spsc_queue_t *pb);
|
||||
|
||||
/**
|
||||
* Test whether a queue is full.
|
||||
*
|
||||
* @param[in] pb : Pointer to SPSC packet queue.
|
||||
* @return : true if the queue is full, false otherwise.
|
||||
*/
|
||||
bool spsc32_is_full(spsc_queue_t *pb);
|
||||
|
||||
#endif /* SPSC_QM_H */
|
|
@ -15,5 +15,13 @@ zephyr_library_sources(
|
|||
timer.c
|
||||
work.c
|
||||
)
|
||||
zephyr_include_directories_ifdef(CONFIG_NRF71_ON_IPC
|
||||
${CMAKE_CURRENT_LIST_DIR}/../bus/
|
||||
${CMAKE_CURRENT_LIST_DIR}/../hw_if/hal/inc
|
||||
)
|
||||
|
||||
zephyr_library_compile_definitions_ifdef(CONFIG_NRF71_ON_IPC
|
||||
NRF71_ON_IPC
|
||||
)
|
||||
|
||||
zephyr_library_link_libraries(nrf-wifi-osal)
|
||||
|
|
|
@ -18,14 +18,19 @@
|
|||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
#ifdef CONFIG_NRF71_ON_IPC
|
||||
#include "ipc_if.h"
|
||||
#else
|
||||
#include <zephyr/drivers/wifi/nrf_wifi/bus/rpu_hw_if.h>
|
||||
#include <zephyr/drivers/wifi/nrf_wifi/bus/qspi_if.h>
|
||||
#endif /* CONFIG_NRF71_ON_IPC */
|
||||
#include <zephyr/sys/math_extras.h>
|
||||
|
||||
#include "shim.h"
|
||||
#include "work.h"
|
||||
#include "timer.h"
|
||||
#include "osal_ops.h"
|
||||
#include "common/hal_structs_common.h"
|
||||
|
||||
LOG_MODULE_REGISTER(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
|
||||
#if defined(CONFIG_NOCACHE_MEMORY)
|
||||
|
@ -122,6 +127,7 @@ static int zep_shim_mem_cmp(const void *addr1,
|
|||
return memcmp(addr1, addr2, size);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
static unsigned int zep_shim_qspi_read_reg32(void *priv, unsigned long addr)
|
||||
{
|
||||
unsigned int val;
|
||||
|
@ -174,6 +180,7 @@ static void zep_shim_qspi_cpy_to(void *priv, unsigned long addr, const void *src
|
|||
|
||||
dev->write(addr, src, count_aligned);
|
||||
}
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
|
||||
static void *zep_shim_spinlock_alloc(void)
|
||||
{
|
||||
|
@ -807,14 +814,56 @@ static enum nrf_wifi_status zep_shim_bus_qspi_dev_init(void *os_qspi_dev_ctx)
|
|||
static void zep_shim_bus_qspi_dev_deinit(void *priv)
|
||||
{
|
||||
struct zep_shim_bus_qspi_priv *qspi_priv = priv;
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
volatile struct qspi_dev *dev = qspi_priv->qspi_dev;
|
||||
|
||||
#else
|
||||
volatile struct rpu_dev *dev = qspi_priv->qspi_dev;
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
dev->deinit();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NRF71_ON_IPC
|
||||
static int ipc_send_msg(unsigned int msg_type, void *msg, unsigned int len)
|
||||
{
|
||||
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
|
||||
struct rpu_dev *dev = rpu_dev();
|
||||
int ret;
|
||||
ipc_ctx_t ctx;
|
||||
|
||||
switch (msg_type) {
|
||||
case NRF_WIFI_HAL_MSG_TYPE_CMD_CTRL:
|
||||
ctx.inst = IPC_INSTANCE_CMD_CTRL;
|
||||
ctx.ept = IPC_EPT_UMAC;
|
||||
break;
|
||||
case NRF_WIFI_HAL_MSG_TYPE_CMD_DATA_TX:
|
||||
ctx.inst = IPC_INSTANCE_CMD_TX;
|
||||
ctx.ept = IPC_EPT_UMAC;
|
||||
break;
|
||||
case NRF_WIFI_HAL_MSG_TYPE_CMD_DATA_RX:
|
||||
ctx.inst = IPC_INSTANCE_RX;
|
||||
ctx.ept = IPC_EPT_LMAC;
|
||||
break;
|
||||
default:
|
||||
nrf_wifi_osal_log_err("%s: Invalid msg_type (%d)", __func__, msg_type);
|
||||
goto out;
|
||||
};
|
||||
|
||||
ret = dev->send(ctx, msg, len);
|
||||
if (ret < 0) {
|
||||
nrf_wifi_osal_log_err("%s: Sending message to RPU failed\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = NRF_WIFI_STATUS_SUCCESS;
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
#endif /* CONFIG_NRF71_ON_IPC */
|
||||
|
||||
static void *zep_shim_bus_qspi_dev_add(void *os_qspi_priv, void *osal_qspi_dev_ctx)
|
||||
{
|
||||
struct zep_shim_bus_qspi_priv *zep_qspi_priv = os_qspi_priv;
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
struct qspi_dev *dev = qspi_dev();
|
||||
int ret;
|
||||
enum nrf_wifi_status status;
|
||||
|
@ -836,6 +885,11 @@ static void *zep_shim_bus_qspi_dev_add(void *os_qspi_priv, void *osal_qspi_dev_c
|
|||
LOG_ERR("%s: RPU enable failed with error %d", __func__, ret);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
struct rpu_dev *dev = rpu_dev();
|
||||
|
||||
dev->init();
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
zep_qspi_priv->qspi_dev = dev;
|
||||
zep_qspi_priv->dev_added = true;
|
||||
|
||||
|
@ -849,8 +903,10 @@ static void zep_shim_bus_qspi_dev_rem(void *priv)
|
|||
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
/* TODO: Make qspi_dev a dynamic instance and remove it here */
|
||||
rpu_disable();
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
}
|
||||
|
||||
static void *zep_shim_bus_qspi_init(void)
|
||||
|
@ -908,6 +964,7 @@ static void zep_shim_bus_qspi_dev_host_map_get(void *os_qspi_dev_ctx,
|
|||
host_map->addr = 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
static void irq_work_handler(struct k_work *work)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -940,6 +997,8 @@ static void zep_shim_irq_handler(const struct device *dev, struct gpio_callback
|
|||
k_work_schedule_for_queue(&zep_wifi_intr_q, &intr_priv->work, K_NO_WAIT);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
|
||||
static enum nrf_wifi_status zep_shim_bus_qspi_intr_reg(void *os_dev_ctx, void *callbk_data,
|
||||
int (*callbk_fn)(void *callbk_data))
|
||||
{
|
||||
|
@ -948,6 +1007,14 @@ static enum nrf_wifi_status zep_shim_bus_qspi_intr_reg(void *os_dev_ctx, void *c
|
|||
|
||||
ARG_UNUSED(os_dev_ctx);
|
||||
|
||||
#ifdef CONFIG_NRF71_ON_IPC
|
||||
ret = ipc_register_rx_cb(callbk_fn, callbk_data);
|
||||
if (ret) {
|
||||
LOG_ERR("%s: ipc_register_rx_cb failed\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
status = NRF_WIFI_STATUS_SUCCESS;
|
||||
#else
|
||||
intr_priv = zep_shim_mem_zalloc(sizeof(*intr_priv));
|
||||
|
||||
if (!intr_priv) {
|
||||
|
@ -970,18 +1037,20 @@ static enum nrf_wifi_status zep_shim_bus_qspi_intr_reg(void *os_dev_ctx, void *c
|
|||
}
|
||||
|
||||
status = NRF_WIFI_STATUS_SUCCESS;
|
||||
|
||||
#endif /* CONFIG_NRF71_ON_IPC */
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void zep_shim_bus_qspi_intr_unreg(void *os_qspi_dev_ctx)
|
||||
{
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
struct k_work_sync sync;
|
||||
int ret;
|
||||
#endif /* !CONFIG_NRF71_ON_IPC */
|
||||
|
||||
ARG_UNUSED(os_qspi_dev_ctx);
|
||||
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
ret = rpu_irq_remove(&intr_priv->gpio_cb_data);
|
||||
if (ret) {
|
||||
LOG_ERR("%s: rpu_irq_remove failed", __func__);
|
||||
|
@ -992,6 +1061,7 @@ static void zep_shim_bus_qspi_intr_unreg(void *os_qspi_dev_ctx)
|
|||
|
||||
zep_shim_mem_free(intr_priv);
|
||||
intr_priv = NULL;
|
||||
#endif /*! CONFIG_NRF71_ON_IPC */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NRF_WIFI_LOW_POWER
|
||||
|
@ -1072,12 +1142,12 @@ const struct nrf_wifi_osal_ops nrf_wifi_os_zep_ops = {
|
|||
.mem_cpy = zep_shim_mem_cpy,
|
||||
.mem_set = zep_shim_mem_set,
|
||||
.mem_cmp = zep_shim_mem_cmp,
|
||||
|
||||
#ifndef CONFIG_NRF71_ON_IPC
|
||||
.qspi_read_reg32 = zep_shim_qspi_read_reg32,
|
||||
.qspi_write_reg32 = zep_shim_qspi_write_reg32,
|
||||
.qspi_cpy_from = zep_shim_qspi_cpy_from,
|
||||
.qspi_cpy_to = zep_shim_qspi_cpy_to,
|
||||
|
||||
#endif /* CONFIG_NRF71_ON_IPC */
|
||||
.spinlock_alloc = zep_shim_spinlock_alloc,
|
||||
.spinlock_free = zep_shim_spinlock_free,
|
||||
.spinlock_init = zep_shim_spinlock_init,
|
||||
|
@ -1157,7 +1227,9 @@ const struct nrf_wifi_osal_ops nrf_wifi_os_zep_ops = {
|
|||
.bus_qspi_ps_wake = zep_shim_bus_qspi_ps_wake,
|
||||
.bus_qspi_ps_status = zep_shim_bus_qspi_ps_status,
|
||||
#endif /* CONFIG_NRF_WIFI_LOW_POWER */
|
||||
|
||||
.assert = zep_shim_assert,
|
||||
.strlen = zep_shim_strlen,
|
||||
#ifdef CONFIG_NRF71_ON_IPC
|
||||
.ipc_send_msg = ipc_send_msg,
|
||||
#endif /* CONFIG_NRF71_ON_IPC */
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue