drivers: wifi: Add nRF70 Wi-Fi driver

Driver for Nordic nRF70 Wi-Fi6 companion chipset, depends on
hal_nordic/nrf_wifi for OS agnostic part of the driver.

This supports (Q)SPI interface to communicate from host to chip.

Signed-off-by: Chaitanya Tata <Chaitanya.Tata@nordicsemi.no>
This commit is contained in:
Chaitanya Tata 2024-06-13 00:02:02 +05:30 committed by Carles Cufí
commit 638ce2fbfd
39 changed files with 13719 additions and 0 deletions

View file

@ -2097,6 +2097,27 @@ Release Notes:
labels:
- "area: Wi-Fi"
"Drivers: Wi-Fi as nRF Wi-Fi":
status: maintained
maintainers:
- krish2718
- jukkar
files:
- drivers/wifi/nrfwifi/
- dts/bindings/wifi/nordic,nrf70.yaml
- dts/bindings/wifi/nordic,nrf70-qspi.yaml
- dts/bindings/wifi/nordic,nrf70-spi.yaml
- dts/bindings/wifi/nordic,nrf70-coex.yaml
- dts/bindings/wifi/nordic,nrf7002-qspi.yaml
- dts/bindings/wifi/nordic,nrf7002-spi.yaml
- dts/bindings/wifi/nordic,nrf7000-qspi.yaml
- dts/bindings/wifi/nordic,nrf7000-spi.yaml
- dts/bindings/wifi/nordic,nrf7001-qspi.yaml
- dts/bindings/wifi/nordic,nrf7001-spi.yaml
- boards/shields/nrf7002ek/
labels:
- "area: Wi-Fi"
"Drivers: Memory Management":
status: maintained
maintainers:

View file

@ -9,3 +9,4 @@ add_subdirectory_ifdef(CONFIG_WIFI_ESWIFI eswifi)
add_subdirectory_ifdef(CONFIG_WIFI_SIMPLELINK simplelink)
add_subdirectory_ifdef(CONFIG_WIFI_WINC1500 winc1500)
add_subdirectory_ifdef(CONFIG_WIFI_AIROC infineon)
add_subdirectory_ifdef(CONFIG_WIFI_NRF70 nrfwifi)

View file

@ -41,5 +41,6 @@ source "drivers/wifi/eswifi/Kconfig.eswifi"
source "drivers/wifi/esp_at/Kconfig.esp_at"
source "drivers/wifi/esp32/Kconfig.esp32"
source "drivers/wifi/infineon/Kconfig.airoc"
source "drivers/wifi/nrfwifi/Kconfig.nrfwifi"
endif # WIFI

View file

@ -0,0 +1,288 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
zephyr_library()
set(OS_AGNOSTIC_BASE ${ZEPHYR_HAL_NORDIC_MODULE_DIR}/drivers/nrf_wifi)
set(FW_BINS_BASE ${ZEPHYR_HAL_NORDIC_MODULE_DIR}/zephyr/blobs/wifi_fw_bins)
zephyr_include_directories(
inc
${OS_AGNOSTIC_BASE}/utils/inc
${OS_AGNOSTIC_BASE}/os_if/inc
${OS_AGNOSTIC_BASE}/bus_if/bus/qspi/inc
${OS_AGNOSTIC_BASE}/bus_if/bal/inc
${OS_AGNOSTIC_BASE}/fw_if/umac_if/inc
${OS_AGNOSTIC_BASE}/fw_load/mips/fw/inc
${OS_AGNOSTIC_BASE}/hw_if/hal/inc
src/qspi/inc
# for net_sprint_ll_addr
${ZEPHYR_BASE}/subsys/net/ip
${OS_AGNOSTIC_BASE}/hw_if/hal/inc/fw
${OS_AGNOSTIC_BASE}/fw_if/umac_if/inc/fw
)
zephyr_include_directories_ifdef(CONFIG_NRF70_RADIO_TEST
${OS_AGNOSTIC_BASE}/fw_if/umac_if/inc/radio_test
)
zephyr_include_directories_ifndef(CONFIG_NRF70_RADIO_TEST
${OS_AGNOSTIC_BASE}/fw_if/umac_if/inc/default
)
zephyr_library_sources_ifdef(CONFIG_NRF70_SR_COEX
src/coex.c
)
zephyr_library_sources(
${OS_AGNOSTIC_BASE}/os_if/src/osal.c
${OS_AGNOSTIC_BASE}/utils/src/list.c
${OS_AGNOSTIC_BASE}/utils/src/queue.c
${OS_AGNOSTIC_BASE}/utils/src/util.c
${OS_AGNOSTIC_BASE}/hw_if/hal/src/hal_api.c
${OS_AGNOSTIC_BASE}/hw_if/hal/src/hal_fw_patch_loader.c
${OS_AGNOSTIC_BASE}/hw_if/hal/src/hal_interrupt.c
${OS_AGNOSTIC_BASE}/hw_if/hal/src/hal_mem.c
${OS_AGNOSTIC_BASE}/hw_if/hal/src/hal_reg.c
${OS_AGNOSTIC_BASE}/hw_if/hal/src/hpqm.c
${OS_AGNOSTIC_BASE}/hw_if/hal/src/pal.c
${OS_AGNOSTIC_BASE}/bus_if/bal/src/bal.c
${OS_AGNOSTIC_BASE}/bus_if/bus/qspi/src/qspi.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/cmd.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/event.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_api_common.c
src/shim.c
src/work.c
src/timer.c
src/fmac_main.c
src/fw_load.c
src/qspi/src/device.c
src/qspi/src/rpu_hw_if.c
src/qspi/src/ficr_prog.c
)
zephyr_library_sources_ifndef(CONFIG_NRF70_RADIO_TEST
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/rx.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_vif.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_util.c
src/net_if.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/default/fmac_api.c
)
zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_MGMT
src/wifi_mgmt_scan.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_SYSTEM_MODE
src/wifi_mgmt.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_SCAN_ONLY
src/wifi_mgmt_scan.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_RADIO_TEST
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/radio_test/fmac_api.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_util.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_DATA_TX
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/tx.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_peer.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_STA_MODE
src/wpa_supp_if.c
src/wifi_mgmt.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_peer.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_util.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_AP_MODE
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_ap.c
)
# Without WPA supplicant we only support scan
zephyr_library_sources_ifdef(CONFIG_NRF70_STA_MODE
src/wpa_supp_if.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_peer.c
${OS_AGNOSTIC_BASE}/fw_if/umac_if/src/fmac_util.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_ON_QSPI
src/qspi/src/qspi_if.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_ON_SPI
src/qspi/src/spi_if.c
)
zephyr_library_sources_ifdef(CONFIG_NRF70_UTIL
src/wifi_util.c
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_ON_QSPI
# These are XIP related anomalies and aren't applicable for nRF7002 and cause
# throughput issues.
-DNRF53_ERRATA_43_ENABLE_WORKAROUND=0
-DNRF52_ERRATA_215_ENABLE_WORKAROUND=0
# nRF70 QSPI doesn't use 192MHz clock and most samples use 128MHz, this can cause anomaly 159
# but as its rare and not seen in most cases, we can disable it.
# Alternative is 128MHz CPU should be disabled that impacts Wi-Fi performance.
-DNRF53_ERRATA_159_ENABLE_WORKAROUND=0
)
# RPU FW patch binaries based on the selected configuration
if(CONFIG_NRF70_SYSTEM_MODE)
set(NRF70_PATCH ${FW_BINS_BASE}/default/nrf70.bin)
elseif(CONFIG_NRF70_RADIO_TEST)
set(NRF70_PATCH ${FW_BINS_BASE}/radio_test/nrf70.bin)
elseif(CONFIG_NRF70_SCAN_ONLY)
set(NRF70_PATCH ${FW_BINS_BASE}/scan_only/nrf70.bin)
elseif (CONFIG_NRF70_SYSTEM_WITH_RAW_MODES)
set(NRF70_PATCH ${FW_BINS_BASE}/system_with_raw/nrf70.bin)
else()
# Error
message(FATAL_ERROR "Unsupported nRF70 patch configuration")
endif()
if(NOT EXISTS ${NRF70_PATCH})
message(FATAL_ERROR "
------------------------------------------------------------------------
Missing blobs for nRF70 device driver, please install by running:
$ west update
$ west blobs fetch hal_nordic
------------------------------------------------------------------------")
endif()
zephyr_compile_definitions(
-DCONFIG_NRF_WIFI_FW_BIN=${NRF70_PATCH}
)
# Translate the configuration to the OS agnostic code
zephyr_compile_definitions_ifdef(CONFIG_NRF_WIFI_LOW_POWER
-DNRF_WIFI_LOW_POWER
)
zephyr_compile_definitions_ifdef(CONFIG_NRF_WIFI_RPU_RECOVERY
-DNRF_WIFI_RPU_RECOVERY
)
zephyr_compile_definitions_ifdef(CONFIG_NRF_WIFI_AP_DEAD_DETECT_TIMEOUT
-DNRF_WIFI_AP_DEAD_DETECT_TIMEOUT=${CONFIG_NRF_WIFI_AP_DEAD_DETECT_TIMEOUT}
)
zephyr_compile_definitions_ifdef(CONFIG_NRF_WIFI_IFACE_MTU
-DNRF_WIFI_IFACE_MTU=${CONFIG_NRF_WIFI_IFACE_MTU}
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_STA_MODE
-DNRF70_STA_MODE
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_DATA_TX
-DNRF70_DATA_TX
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_RAW_DATA_TX
-DNRF70_RAW_DATA_TX
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_RAW_DATA_RX
-DNRF70_RAW_DATA_RX
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_PROMISC_DATA_RX
-DNRF70_PROMISC_DATA_RX
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_TX_DONE_WQ_ENABLED
-DNRF70_TX_DONE_WQ_ENABLED
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_RX_WQ_ENABLED
-DNRF70_RX_WQ_ENABLED
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_UTIL
-DNRF70_UTIL
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_RADIO_TEST
-DNRF70_RADIO_TEST
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_TCP_IP_CHECKSUM_OFFLOAD
-DNRF70_TCP_IP_CHECKSUM_OFFLOAD
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_RPU_EXTEND_TWT_SP
-DNRF70_RPU_EXTEND_TWT_SP
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_SYSTEM_WITH_RAW_MODES
-DNRF70_SYSTEM_WITH_RAW_MODES
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_SCAN_ONLY
-DNRF70_SCAN_ONLY
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_SYSTEM_MODE
-DNRF70_SYSTEM_MODE
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_2_4G_ONLY
-DNRF70_2_4G_ONLY
)
zephyr_compile_definitions_ifdef(CONFIG_NRF70_LOG_VERBOSE
-DNRF70_LOG_VERBOSE
)
zephyr_compile_definitions(
-DNRF70_RX_NUM_BUFS=${CONFIG_NRF70_RX_NUM_BUFS}
-DNRF70_MAX_TX_TOKENS=${CONFIG_NRF70_MAX_TX_TOKENS}
-DNRF70_RX_MAX_DATA_SIZE=${CONFIG_NRF70_RX_MAX_DATA_SIZE}
-DNRF70_MAX_TX_PENDING_QLEN=${CONFIG_NRF70_MAX_TX_PENDING_QLEN}
-DNRF70_RPU_PS_IDLE_TIMEOUT_MS=${CONFIG_NRF70_RPU_PS_IDLE_TIMEOUT_MS}
-DNRF70_REG_DOMAIN=${CONFIG_NRF70_REG_DOMAIN}
-DNRF70_BAND_2G_LOWER_EDGE_BACKOFF_DSSS=${CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_DSSS}
-DNRF70_BAND_2G_LOWER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HT}
-DNRF70_BAND_2G_LOWER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HE}
-DNRF70_BAND_2G_UPPER_EDGE_BACKOFF_DSSS=${CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_DSSS}
-DNRF70_BAND_2G_UPPER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HT}
-DNRF70_BAND_2G_UPPER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HE}
-DNRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HT=${CONFIG_NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HT}
-DNRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HE=${CONFIG_NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HE}
-DNRF70_PCB_LOSS_2G=${CONFIG_NRF70_PCB_LOSS_2G}
-DNRF70_PCB_LOSS_5G_BAND1=${CONFIG_NRF70_PCB_LOSS_5G_BAND1}
-DNRF70_PCB_LOSS_5G_BAND2=${CONFIG_NRF70_PCB_LOSS_5G_BAND2}
-DNRF70_PCB_LOSS_5G_BAND3=${CONFIG_NRF70_PCB_LOSS_5G_BAND3}
-DNRF70_ANT_GAIN_2G=${CONFIG_NRF70_ANT_GAIN_2G}
-DNRF70_ANT_GAIN_5G_BAND1=${CONFIG_NRF70_ANT_GAIN_5G_BAND1}
-DNRF70_ANT_GAIN_5G_BAND2=${CONFIG_NRF70_ANT_GAIN_5G_BAND2}
-DNRF70_ANT_GAIN_5G_BAND3=${CONFIG_NRF70_ANT_GAIN_5G_BAND3}
)

View file

@ -0,0 +1,670 @@
# Nordic Wi-Fi driver for nRF70 series SoCs
#
# Copyright (c) 2024 Nordic Semiconductor
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig WIFI_NRF70
bool "nRF70 driver"
select NET_L2_WIFI_MGMT if NETWORKING
select NET_L2_ETHERNET_MGMT if NETWORKING && NET_L2_ETHERNET
select WIFI_USE_NATIVE_NETWORKING if NETWORKING
select EXPERIMENTAL if !SOC_SERIES_NRF53X && !SOC_SERIES_NRF91X
default y
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
help
Nordic Wi-Fi Driver
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
config WIFI_NRF7001
bool
default y if DT_HAS_NORDIC_NRF7001_SPI_ENABLED || DT_HAS_NORDIC_NRF7001_QSPI_ENABLED
config WIFI_NRF7000
bool
default y if DT_HAS_NORDIC_NRF7000_SPI_ENABLED || DT_HAS_NORDIC_NRF7000_QSPI_ENABLED
module = WIFI_NRF70_BUS
module-dep = LOG
module-str = Log level for Wi-Fi nRF70 bus layers
module-help = Sets log level for Wi-Fi nRF70 bus layers
source "subsys/net/Kconfig.template.log_config.net"
config WIFI_NRF70_BUS_LOG_LEVEL
# Enable error by default
default 1
choice NRF70_OPER_MODES
bool "nRF70 operating modes"
default NRF70_SYSTEM_WITH_RAW_MODES if !WIFI_NRF7000 && \
(NRF70_RAW_DATA_TX || NRF70_RAW_DATA_RX || NRF70_PROMISC_DATA_RX)
default NRF70_SYSTEM_MODE if !WIFI_NRF7000
default NRF70_SCAN_ONLY if WIFI_NRF7000
help
Select the operating mode of the nRF70 driver
config NRF70_SYSTEM_MODE
bool "nRF70 system mode"
depends on WIFI_NRF7002 || WIFI_NRF7001
select WIFI_NM_WPA_SUPPLICANT
help
Select this option to enable system mode of the nRF70 driver
config NRF70_SCAN_ONLY
bool "nRF70 scan only mode"
depends on WIFI_NRF7000
help
Select this option to enable scan only mode of the nRF70 driver
config NRF70_RADIO_TEST
bool "Radio test mode of the nRF70 driver"
config NRF70_SYSTEM_WITH_RAW_MODES
bool "nRF70 system mode with raw modes"
depends on WIFI_NRF7002 || WIFI_NRF7001
select WIFI_NM_WPA_SUPPLICANT
help
Select this option to enable system mode of the nRF70 driver with raw modes
endchoice
config NET_L2_ETHERNET
default y if !NRF70_RADIO_TEST
config HEAP_MEM_POOL_ADD_SIZE_NRF70
# Use a maximum that works for typical usecases and boards, each sample/app can override
# this value if needed by using CONFIG_HEAP_MEM_POOL_IGNORE_MIN
def_int 25000 if NRF70_SCAN_ONLY
def_int 150000
if NRF70_SYSTEM_MODE || NRF70_SYSTEM_WITH_RAW_MODES
config NRF70_STA_MODE
bool "nRF70 STA mode"
default y
help
Select this option to enable STA mode of the nRF70 driver
config NRF70_AP_MODE
bool "Access point mode"
depends on WIFI_NM_WPA_SUPPLICANT_AP
config NRF70_P2P_MODE
bool "P2P support in driver"
endif # NRF70_SYSTEM_MODE || NRF70_SYSTEM_WITH_RAW_MODES
config NRF70_RAW_DATA_TX
bool "RAW TX data path in the driver"
select EXPERIMENTAL
config NRF70_RAW_DATA_RX
bool "RAW RX sniffer operation in the driver"
select EXPERIMENTAL
config NRF70_PROMISC_DATA_RX
bool "promiscuous RX sniffer operation in the driver"
select WIFI_NM_WPA_SUPPLICANT
select EXPERIMENTAL
select NET_PROMISCUOUS_MODE
config NRF70_DATA_TX
bool "TX data path in the driver"
default y if NRF70_SYSTEM_MODE || NRF70_SYSTEM_WITH_RAW_MODES
config NRF_WIFI_IF_AUTO_START
bool "Wi-Fi interface auto start on boot"
default y
config NRF_WIFI_PATCHES_BUILTIN
bool "Store nRF70 FW patches as part of the driver"
default y
help
Select this option to store nRF70 FW patches as part of the driver.
This option impacts the code memory footprint of the driver.
config CUSTOM_LINKER_SCRIPT
string "Custom linker script for nRF70 FW patches"
default "${ZEPHYR_BASE}/../nrf/drivers/wifi/nrf70/rpu_fw_patches.ld"
config NRF_WIFI_LOW_POWER
bool "low power mode in nRF Wi-Fi chipsets"
default y
config NRF70_TCP_IP_CHECKSUM_OFFLOAD
bool "TCP/IP checksum offload"
default y
config NRF70_REG_DOMAIN
string "The ISO/IEC alpha2 country code for the country in which this device is currently operating. Default 00 (World regulatory)"
# 00 is used for World regulatory
default "00"
# Making calls to RPU from net_mgmt callbacks.
#
# If WPA supplicant is enabled, then don't override as it has higher
# stack requirements.
config NET_MGMT_EVENT_STACK_SIZE
default 2048 if !WIFI_NM_WPA_SUPPLICANT
config NRF70_LOG_VERBOSE
bool "Maintains the verbosity of information in logs"
default y
module = WIFI_NRF70
module-dep = LOG
module-str = Log level for Wi-Fi nRF70 driver
module-help = Sets log level for Wi-Fi nRF70 driver
source "subsys/logging/Kconfig.template.log_config"
config WIFI_NRF70_LOG_LEVEL
# Enable error by default
default 1
config NRF70_ON_QSPI
def_bool DT_HAS_NORDIC_NRF7002_QSPI_ENABLED || \
DT_HAS_NORDIC_NRF7001_QSPI_ENABLED || \
DT_HAS_NORDIC_NRF7000_QSPI_ENABLED
select NRFX_QSPI
config NRF70_ON_SPI
def_bool DT_HAS_NORDIC_NRF7002_SPI_ENABLED || \
DT_HAS_NORDIC_NRF7001_SPI_ENABLED || \
DT_HAS_NORDIC_NRF7000_SPI_ENABLED
select SPI
config NRF70_2_4G_ONLY
def_bool y if WIFI_NRF7001
# Wi-Fi and SR Coexistence Hardware configuration.
config NRF70_SR_COEX
bool "Wi-Fi and SR coexistence support"
config NRF70_SR_COEX_RF_SWITCH
bool "GPIO configuration to control SR side RF switch position"
config NRF70_WORKQ_STACK_SIZE
int "Stack size for workqueue"
default 4096
config NRF70_WORKQ_MAX_ITEMS
int "Maximum work items for all workqueues"
default 100
config NRF70_MAX_TX_PENDING_QLEN
int "Maximum number of pending TX packets"
default 18
config NRF70_UTIL
depends on SHELL
bool "Utility shell in nRF70 driver"
config NRF70_QSPI_LOW_POWER
bool "low power mode in QSPI"
default y if NRF_WIFI_LOW_POWER
config NRF70_PCB_LOSS_2G
int "PCB loss for 2.4 GHz band"
default 0
range 0 4
help
Specifies PCB loss from the antenna connector to the RF pin.
The values are in dB scale in steps of 1dB and range of 0-4dB.
The loss is considered in the RX path only.
config NRF70_PCB_LOSS_5G_BAND1
int "PCB loss for 5 GHz band (5150 MHz - 5350 MHz, Channel-32 - Channel-68)"
default 0
range 0 4
help
Specifies PCB loss from the antenna connector to the RF pin.
The values are in dB scale in steps of 1dB and range of 0-4dB.
The loss is considered in the RX path only.
config NRF70_PCB_LOSS_5G_BAND2
int "PCB loss for 5 GHz band (5470 MHz - 5730 MHz, Channel-96 - Channel-144)"
default 0
range 0 4
help
Specifies PCB loss from the antenna connector to the RF pin.
The values are in dB scale in steps of 1dB and range of 0-4dB.
The loss is considered in the RX path only.
config NRF70_PCB_LOSS_5G_BAND3
int "PCB loss for 5 GHz band (5730 MHz - 5895 MHz, Channel-149 - Channel-177)"
default 0
range 0 4
help
Specifies PCB loss from the antenna connector to the RF pin.
The values are in dB scale in steps of 1dB and range of 0-4dB.
The loss is considered in the RX path only.
config NRF70_ANT_GAIN_2G
int "Antenna gain for 2.4 GHz band"
default 0
range 0 6
config NRF70_ANT_GAIN_5G_BAND1
int "Antenna gain for 5 GHz band (5150 MHz - 5350 MHz)"
default 0
range 0 6
config NRF70_ANT_GAIN_5G_BAND2
int "Antenna gain for 5 GHz band (5470 MHz - 5730 MHz)"
default 0
range 0 6
config NRF70_ANT_GAIN_5G_BAND3
int "Antenna gain for 5 GHz band (5730 MHz - 5895 MHz)"
default 0
range 0 6
config NRF70_BAND_2G_LOWER_EDGE_BACKOFF_DSSS
int "DSSS Transmit power backoff (in dB) for lower edge of 2.4 GHz frequency band"
default 0
range 0 10
config NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for lower edge of 2.4 GHz frequency band"
default 0
range 0 10
config NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for lower edge of 2.4 GHz frequency band"
default 0
range 0 10
config NRF70_BAND_2G_UPPER_EDGE_BACKOFF_DSSS
int "DSSS Transmit power backoff (in dB) for upper edge of 2.4 GHz frequency band"
default 0
range 0 10
config NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for upper edge of 2.4 GHz frequency band"
default 0
range 0 10
config NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for upper edge of 2.4 GHz frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for lower edge of UNII-1 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for lower edge of UNII-1 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for upper edge of UNII-1 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for upper edge of UNII-1 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for lower edge of UNII-2A frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for lower edge of UNII-2A frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for upper edge of UNII-2A frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for upper edge of UNII-2A frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for lower edge of UNII-2C frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for lower edge of UNII-2C frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for upper edge of UNII-2C frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for upper edge of UNII-2C frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for lower edge of UNII-3 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for lower edge of UNII-3 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for upper edge of UNII-3 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for upper edge of UNII-3 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for lower edge of UNII-4 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for lower edge of UNII-4 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HT
int "HT/VHT Transmit power backoff (in dB) for upper edge of UNII-4 frequency band"
default 0
range 0 10
config NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HE
int "HE Transmit power backoff (in dB) for upper edge of UNII-4 frequency band"
default 0
range 0 10
# Performance fine tuning options
config NRF70_RX_NUM_BUFS
int "Number of RX buffers"
default 48
config NRF70_MAX_TX_AGGREGATION
int "Maximum number of TX packets to aggregate"
default 12
config NRF70_MAX_TX_TOKENS
int "Maximum number of TX tokens"
range 5 12 if !NRF70_RADIO_TEST
default 10
config NRF70_TX_MAX_DATA_SIZE
int "Maximum size of TX data"
default 1600
config NRF70_RX_MAX_DATA_SIZE
int "Maximum size of RX data"
default 1600
config NRF70_TX_DONE_WQ_ENABLED
bool "TX done workqueue (impacts performance negatively)"
config NRF70_RX_WQ_ENABLED
bool "RX workqueue"
# Use for IRQ processing (TODO: using for BH processing causes issues)
config NUM_METAIRQ_PRIORITIES
default 1
config NRF70_IRQ_WQ_PRIORITY
int "Priority of the workqueue for handling IRQs"
default -15
config NRF70_BH_WQ_PRIORITY
int "Priority of the workqueue for handling bottom half"
default 0
config NRF70_IRQ_WQ_STACK_SIZE
int "Stack size of the workqueue for handling IRQs"
default 2048
config NRF70_BH_WQ_STACK_SIZE
int "Stack size of the workqueue for handling bottom half"
default 2048
if NRF70_TX_DONE_WQ_ENABLED
config NRF70_TX_DONE_WQ_PRIORITY
int "Priority of the workqueue for handling TX done"
default 0
config NRF70_TX_DONE_WQ_STACK_SIZE
int "Stack size of the workqueue for handling TX done"
default 2048
endif # NRF70_TX_DONE_WQ_ENABLED
if NRF70_RX_WQ_ENABLED
config NRF70_RX_WQ_PRIORITY
int "Priority of the workqueue for handling RX"
default 0
config NRF70_RX_WQ_STACK_SIZE
int "Stack size of the workqueue for handling RX"
default 2048
endif # NRF70_RX_WQ_ENABLED
if NRF_WIFI_LOW_POWER
config NRF70_RPU_PS_IDLE_TIMEOUT_MS
int "RPU power save idle timeout in milliseconds"
default 10
config NRF70_RPU_EXTEND_TWT_SP
bool "extending TWT service period"
help
In case frames accepted before beginning of SP are not
transmitted before the SP completes then typically they are
dropped to conform to SP window as per specification i.e., no
transmission outside SP window.
This feature mitigates the frame loss by transmitting even after SP
completion by using standard contention mechanism which is allowed
in specification but not recommended. As the device is actively transmitting
beyond SP, the power consumption increases depending on the amount
of traffic available at the start of SP.
Please note that if a frame is sent after SP starts it will be queued and this
mechanism is not used.
endif # NRF_WIFI_LOW_POWER
config WIFI_FIXED_MAC_ADDRESS
string "WiFi Fixed MAC address in format XX:XX:XX:XX:XX:XX"
help
This overrides the MAC address read from OTP. Strictly for testing purposes only.
choice
prompt "Wi-Fi MAC address type"
default WIFI_OTP_MAC_ADDRESS if WIFI_FIXED_MAC_ADDRESS = ""
default WIFI_FIXED_MAC_ADDRESS_ENABLED if WIFI_FIXED_MAC_ADDRESS != ""
help
Select the type of MAC address to be used by the Wi-Fi driver
config WIFI_OTP_MAC_ADDRESS
bool "Use MAC address from OTP"
help
This option uses the MAC address stored in the OTP memory of the nRF70.
config WIFI_FIXED_MAC_ADDRESS_ENABLED
bool "fixed MAC address"
help
Enable fixed MAC address
config WIFI_RANDOM_MAC_ADDRESS
bool "random MAC address generation at runtime"
depends on ENTROPY_GENERATOR
help
This option enables random MAC address generation at runtime.
The random MAC address is generated using the entropy device random generator.
endchoice
config NRF70_RSSI_STALE_TIMEOUT_MS
int "RSSI stale timeout in milliseconds"
default 1000
help
RSSI stale timeout is the period after which driver queries
RPU to get the RSSI the value.
If data is active (e.g. ping), driver stores the RSSI value from
the received frames and provides this stored information
to wpa_supplicant. In this case a higher value will be suitable
as stored RSSI value at driver will be updated regularly.
If data is not active or after the stale timeout duration,
driver queries the RPU to get the RSSI value
and provides it to wpa_supplicant. The value should be set to lower
value as driver does not store it and requires RPU to provide the
info.
if NETWORKING
# Finetune defaults for certain system components used by the driver
config SYSTEM_WORKQUEUE_STACK_SIZE
default 4096
config NET_TX_STACK_SIZE
default 4096
config NET_RX_STACK_SIZE
default 4096
config NET_TC_TX_COUNT
default 1
endif # NETWORKING
config MAIN_STACK_SIZE
default 4096
config SHELL_STACK_SIZE
default 4096
# Override the Wi-Fi subsytems WIFI_MGMT_SCAN_SSID_FILT_MAX parameter,
# since we support a maximum of 2 SSIDs for scan result filtering.
config WIFI_MGMT_SCAN_SSID_FILT_MAX
default 2
config NRF_WIFI_SCAN_MAX_BSS_CNT
int "Maximum number of scan results to return."
default 0
range 0 65535
help
Maximum number of scan results to return. 0 represents unlimited number of BSSes.
config NRF_WIFI_BEAMFORMING
bool "Wi-Fi beamforming. Enabling beamforming can provide slight improvement in performance where as disabling it can provide better power saving in low network activity applications"
default y
config WIFI_NRF70_SCAN_TIMEOUT_S
int "Scan timeout in seconds"
default 30
menu "nRF Wi-Fi operation band(s)"
visible if !NRF70_2_4G_ONLY
config NRF_WIFI_2G_BAND
bool "Set operation band to 2.4GHz"
default y if NRF70_2_4G_ONLY
config NRF_WIFI_5G_BAND
bool "Set operation band to 5GHz"
depends on !NRF70_2_4G_ONLY
config NRF_WIFI_OP_BAND
int "Options to set operation band"
default 1 if NRF_WIFI_2G_BAND
default 2 if NRF_WIFI_5G_BAND
default 3
help
Set this option to select frequency band
1 - 2.4GHz
2 - 5GHz
3 - All ( 2.4GHz and 5GHz )
endmenu
config NRF_WIFI_IFACE_MTU
int "MTU for Wi-Fi interface"
range 576 2304 if NET_IPV4
range 1280 2304 if NET_IPV6
default 1500
config WIFI_NRF70_SKIP_LOCAL_ADMIN_MAC
bool "Suppress networks with non-individual MAC address as BSSID in the scan results"
help
Wi-Fi access points use locally administered MAC address to manage
multiple virtual interfaces, for geo-location usecase these networks
from the virtual interfaces do not help in anyway as they are co-located with the primary interface
that has globally unique MAC address.
So, to save resources, this option drops such networks from the scan results.
config WIFI_NRF70_SCAN_DISABLE_DFS_CHANNELS
bool "Disables DFS channels in scan operation"
help
This option disables inclusion of DFS channels in scan operation.
This is useful to reduce the scan time, as DFS channels are seldom used.
config NET_INTERFACE_NAME_LEN
# nordic_wlanN
default 15
config NRF_WIFI_AP_DEAD_DETECT_TIMEOUT
int "Access point dead detection timeout in seconds"
range 1 30
default 20
help
The number of seconds after which AP is declared dead if no beacons
are received from the AP. Used to detect AP silently going down e.g., power off.
config NRF_WIFI_RPU_RECOVERY
bool "RPU recovery mechanism"
select EXPERIMENTAL
help
Enable RPU recovery mechanism to recover from RPU (nRF70) hang.
This feature performs an interface reset (down and up) which triggers
a RPU coldboot. Application's network connection will be lost during
the recovery process and it is application's responsibility to
re-establish the network connection.
if NRF_WIFI_RPU_RECOVERY
config NRF_WIFI_RPU_RECOVERY_PROPAGATION_DELAY_MS
int "RPU recovery propagation delay in milliseconds"
default 10
help
Propagation delay in milliseconds to wait after RPU is powered down
before powering it up. This delay is required to ensure that the recovery
is propagted to all the applications and stack and have enough time to
clean up the resources.
config NET_MGMT_EVENT_QUEUE_SIZE
# Doing interface down and up even with delay puts a lot of events in the queue
default 16
endif # NRF_WIFI_RPU_RECOVERY
config NRF_WIFI_COMBINED_BUCKEN_IOVDD_GPIO
bool
help
Enable this option to use a single GPIO to control both buck enable and IOVDD enable,
there will be a internal hardware switch to add delay between the two operations. This
is typically 4ms delay for nRF70.
endif # WIFI_NRF70

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing Coexistence APIs.
*/
#ifndef __COEX_H__
#define __COEX_H__
#include <stdbool.h>
/* Indicates WLAN frequency band of operation */
enum nrf_wifi_pta_wlan_op_band {
NRF_WIFI_PTA_WLAN_OP_BAND_2_4_GHZ = 0,
NRF_WIFI_PTA_WLAN_OP_BAND_5_GHZ,
NRF_WIFI_PTA_WLAN_OP_BAND_NONE = 0xFF
};
/**
* @function nrf_wifi_coex_config_pta(enum nrf_wifi_pta_wlan_op_band wlan_band,
* bool separate_antennas, bool is_sr_protocol_ble)
*
* @brief Function used to configure PTA tables of coexistence hardware.
*
* @param[in] enum nrf_wifi_pta_wlan_op_band wlan_band
* @param[in] separate_antennas
* Indicates whether separate antenans are used or not.
* @param[in] is_sr_protocol_ble
* Indicates if SR protocol is Bluetooth LE or not.
* @return Returns status of configuration.
* Returns zero upon successful configuration.
* Returns non-zero upon unsuccessful configuration.
*/
int nrf_wifi_coex_config_pta(enum nrf_wifi_pta_wlan_op_band wlan_band, bool separate_antennas,
bool is_sr_protocol_ble);
#if defined(CONFIG_NRF70_SR_COEX_RF_SWITCH) || defined(__DOXYGEN__)
/**
* @function nrf_wifi_config_sr_switch(bool separate_antennas)
*
* @brief Function used to configure SR side switch (nRF5340 side switch in nRF7002 DK).
*
* @param[in] separate_antennas
* Indicates whether separate antenans are used or not.
*
* @return Returns status of configuration.
* Returns zero upon successful configuration.
* Returns non-zero upon unsuccessful configuration.
*/
int nrf_wifi_config_sr_switch(bool separate_antennas);
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
/**
* @function nrf_wifi_coex_config_non_pta(bool separate_antennas)
*
* @brief Function used to configure non-PTA registers of coexistence hardware.
*
* @param[in] separate_antennas
* Indicates whether separate antenans are used or not.
* @param[in] is_sr_protocol_ble
* Indicates if SR protocol is Bluetooth LE or not.
*
* @return Returns status of configuration.
* Returns zero upon successful configuration.
* Returns non-zero upon unsuccessful configuration.
*/
int nrf_wifi_coex_config_non_pta(bool separate_antennas, bool is_sr_protocol_ble);
/**
* @function nrf_wifi_coex_hw_reset(void)
*
* @brief Function used to reset coexistence hardware.
*
* @return Returns status of configuration.
* Returns zero upon successful configuration.
* Returns non-zero upon unsuccessful configuration.
*/
int nrf_wifi_coex_hw_reset(void);
#endif /* __COEX_H__ */

View file

@ -0,0 +1,182 @@
/**
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Structures and related enumerations used in Coexistence.
*/
#ifndef __COEX_STRUCT_H__
#define __COEX_STRUCT_H__
#include <stdint.h>
#include <stdbool.h>
/* Max size of message buffer (exchanged between host and MAC). This is in "bytes" */
#define MAX_MESSAGE_BUF_SIZE 320
/* Number of elements in coex_ch_configuration other than configbuf[] */
#define NUM_ELEMENTS_EXCL_CONFIGBUF 4
/* Each configuration value is of type uint32_t */
#define MAX_NUM_CONFIG_VALUES ((MAX_MESSAGE_BUF_SIZE-\
(NUM_ELEMENTS_EXCL_CONFIGBUF*sizeof(uint32_t)))>>2)
/* Number of elements in coex_sr_traffic_info other than sr_traffic_info[] */
#define NUM_ELEMENTS_EXCL_SRINFOBUF 1
/* Each SR Traffic Info is of type uint32_t */
#define MAX_SR_TRAFFIC_BUF_SIZE 32
enum {
/** Used two different values for AGGREGATION module because offset from base is
* beyond supported message buffer size for WAIT_STATE_1_TIME register
*/
COEX_HARDWARE = 1,
MAC_CTRL,
MAC_CTRL_AGG_WAIT_STATE_1_TIME,
MAC_CTRL_AGG,
MAC_CTRL_DEAGG,
WLAN_CTRL,
};
/* IDs of different messages posted from Coexistence Driver to Coexistence Manager */
enum {
/* To insturct Coexistence Manager to collect and post SR traffic information */
COLLECT_SR_TRAFFIC_INFO = 1,
/* To insturct Coexistence Manager to allocate a priority window to SR */
ALLOCATE_PTI_WINDOW,
/* To do configuration of hardware related to coexistence */
HW_CONFIGURATION,
/* To start allocating periodic priority windows to Wi-Fi and SR */
ALLOCATE_PPW,
/* To start allocating virtual priority windows to Wi-Fi */
ALLOCATE_VPW,
/* To configure CM SW parameters */
SW_CONFIGURATION,
/* To control sheliak side switch */
UPDATE_SWITCH_CONFIG
};
/* ID(s) of different messages posted from Coexistence Manager to Coexistence Driver */
enum {
/* To post SR traffic information */
SR_TRAFFIC_INFO = 1
};
/**
* struct coex_collect_sr_traffic_info - Message from CD to CM to request SR traffic info.
* @message_id: Indicates message ID. This is to be set to COLLECT_SR_TRAFFIC_INFO.
* @num_sets_requested: Indicates the number of sets of duration and periodicity to be collected.
*
* Message from CD to CM to request SR traffic information.
*/
struct coex_collect_sr_traffic_info {
uint32_t message_id;
uint32_t num_sets_requested;
};
/**
* struct coex_ch_configuration -Message from CD to CM to configure CH.
* @message_id: Indicates message ID. This is to be set to HW_CONFIGURATION.
* @num_reg_to_config: Indicates the number of registers to be configured.
* @hw_to_config: Indicates the hardware block that is to be configured.
* @hw_block_base_addr: Base address of the hardware block to be configured.
* @configbuf: Configuration buffer that holds packed offset and configuration value.
*
* Message from CD to CM to configure CH
*/
struct coex_ch_configuration {
uint32_t message_id;
uint32_t num_reg_to_config;
uint32_t hw_to_config;
uint32_t hw_block_base_addr;
uint32_t configbuf[MAX_NUM_CONFIG_VALUES];
};
/**
* struct coex_allocate_pti_window - Message to CM to request a priority window.
* @message_id: Indicates message ID. This is to be set to ALLOCATE_PTI_WINDOW.
* @device_req_window: Indicates device requesting a priority window.
* @window_start_or_end: Indicates if request is posted to START or END a priority window.
* @imp_of_request: Indicates importance of activity for which the window is requested.
* @can_be_deferred: activity of Wi-Fi/SR, for which window is requested can be deferred or not.
*
* Message to CM to request a priority window
*/
struct coex_allocate_pti_window {
uint32_t message_id;
uint32_t device_req_window;
uint32_t window_start_or_end;
uint32_t imp_of_request;
uint32_t can_be_deferred;
};
/**
* struct coex_allocate_ppw - Message from CD to CM to allocate Periodic Priority Windows.
* @message_id: Indicates message ID. This is to be set to ALLOCATE_PPW.
* @start_or_stop: Indiates start or stop allocation of PPWs.
* @first_pti_window: Indicates first priority window in the series of PPWs.
* @ps_mechanism: Indicates recommended powersave mechanism for Wi-Fi's downlink.
* @wifi_window_duration: Indicates duration of Wi-Fi priority window.
* @sr_window_duration: Indicates duration of SR priority window.
*
* Message from CD to CM to allocate Periodic Priority Windows.
*/
struct coex_allocate_ppw {
uint32_t message_id;
uint32_t start_or_stop;
uint32_t first_pti_window;
uint32_t ps_mechanism;
uint32_t wifi_window_duration;
uint32_t sr_window_duration;
};
/**
* struct coex_allocate_vpw - Message from CD to CM to allocate Virtual Priority Windows.
* @message_id: Indicates message ID. This is to be set to ALLOCATE_VPW.
* @start_or_stop: Indicates start or stop allocation of VPWs.
* @wifi_window_duration: Indicates duration of Wi-Fi virtual priority window.
* @ps_mechanism: Indicates recommended powersave mechanism for Wi-Fi's downlink.
*
* Message from CD to CM to allocate Virtual Priority Windows.
*/
struct coex_allocate_vpw {
uint32_t message_id;
uint32_t start_or_stop;
uint32_t wifi_window_duration;
uint32_t ps_mechanism;
};
/**
* struct coex_config_cm_params - Message from CD to CM to configure CM parameters
* @message_id: Indicates message ID. This is to be set to SW_CONFIGURATION.
* @first_isr_trigger_period: microseconds . used to trigger the ISR mechanism.
* @sr_window_poll_periodicity_vpw: microseconds. This is used to poll through SR window.
* that comes after Wi-Fi window ends and next SR activity starts, in the case of VPWs.
* @lead_time_from_end_of_wlan_win: microseconds. Lead time from the end of Wi-Fi window.
* (to inform AP that Wi-Fi is entering powersave) in the case of PPW and VPW generation.
* @sr_window_poll_count_threshold: This is equal to "Wi-Fi contention timeout.
* threshold"/sr_window_poll_periodicity_vpw.
*
* Message from CD to CM to configure CM parameters.
*/
struct coex_config_cm_params {
uint32_t message_id;
uint32_t first_isr_trigger_period;
uint32_t sr_window_poll_periodicity_vpw;
uint32_t lead_time_from_end_of_wlan_win;
uint32_t sr_window_poll_count_threshold;
};
/**
* struct coex_sr_traffic_info - Message from CM to CD to post SR traffic information.
* @message_id: Indicates message ID. This is to be set to SR_TRAFFIC_INFO.
* @sr_traffic_info: Traffic information buffer.
*
* Message from CM to CD to post SR traffic inforamtion
*/
struct coex_sr_traffic_info {
uint32_t message_id;
uint32_t sr_traffic_info[MAX_SR_TRAFFIC_BUF_SIZE];
};
#endif /* __COEX_STRUCT_H__ */

View file

@ -0,0 +1,133 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing FMAC interface specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __ZEPHYR_FMAC_MAIN_H__
#define __ZEPHYR_FMAC_MAIN_H__
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/version.h>
#include <zephyr/net/net_if.h>
#ifndef CONFIG_NRF70_RADIO_TEST
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/ethernet.h>
#ifdef CONFIG_NETWORKING
#include <net_if.h>
#endif /* CONFIG_NETWORKING */
#ifdef CONFIG_NRF70_STA_MODE
#include <drivers/driver_zephyr.h>
#endif /* CONFIG_NRF70_STA_MODE */
#endif /* !CONFIG_NRF70_RADIO_TEST */
#include <fmac_api.h>
#include <host_rpu_umac_if.h>
#define NRF70_DRIVER_VERSION "1."KERNEL_VERSION_STRING
#ifndef CONFIG_NRF70_RADIO_TEST
struct nrf_wifi_vif_ctx_zep {
const struct device *zep_dev_ctx;
struct net_if *zep_net_if_ctx;
void *supp_drv_if_ctx;
void *rpu_ctx_zep;
unsigned char vif_idx;
struct k_mutex vif_lock;
scan_result_cb_t disp_scan_cb;
bool scan_in_progress;
int scan_type;
uint16_t max_bss_cnt;
unsigned int scan_res_cnt;
struct k_work_delayable scan_timeout_work;
struct net_eth_addr mac_addr;
int if_type;
char ifname[16];
enum nrf_wifi_fmac_if_op_state if_op_state;
bool set_if_event_received;
int set_if_status;
#ifdef CONFIG_NET_STATISTICS_ETHERNET
struct net_stats_eth eth_stats;
#endif /* CONFIG_NET_STATISTICS_ETHERNET */
#ifdef CONFIG_NRF70_STA_MODE
unsigned int assoc_freq;
enum nrf_wifi_fmac_if_carr_state if_carr_state;
struct wpa_signal_info *signal_info;
struct wpa_conn_info *conn_info;
struct zep_wpa_supp_dev_callbk_fns supp_callbk_fns;
unsigned char twt_flows_map;
unsigned char twt_flow_in_progress_map;
struct wifi_ps_config *ps_info;
bool ps_config_info_evnt;
bool authorized;
bool cookie_resp_received;
#ifdef CONFIG_NRF70_DATA_TX
struct k_work nrf_wifi_net_iface_work;
#endif /* CONFIG_NRF70_DATA_TX */
unsigned long rssi_record_timestamp_us;
signed short rssi;
#endif /* CONFIG_NRF70_STA_MODE */
#ifdef CONFIG_NRF70_AP_MODE
int inactive_time_sec;
#endif /* CONFIG_NRF70_AP_MODE */
#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
struct k_work nrf_wifi_rpu_recovery_work;
#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
};
struct nrf_wifi_vif_ctx_map {
const char *ifname;
struct nrf_wifi_vif_ctx_zep *vif_ctx;
};
#endif /* !CONFIG_NRF70_RADIO_TEST */
struct nrf_wifi_ctx_zep {
void *drv_priv_zep;
void *rpu_ctx;
#ifdef CONFIG_NRF70_RADIO_TEST
struct rpu_conf_params conf_params;
bool rf_test_run;
unsigned char rf_test;
#else /* CONFIG_NRF70_RADIO_TEST */
struct nrf_wifi_vif_ctx_zep vif_ctx_zep[MAX_NUM_VIFS];
#ifdef CONFIG_NRF70_UTIL
struct rpu_conf_params conf_params;
#endif /* CONFIG_NRF70_UTIL */
#endif /* CONFIG_NRF70_RADIO_TEST */
unsigned char *extended_capa, *extended_capa_mask;
unsigned int extended_capa_len;
struct k_mutex rpu_lock;
};
struct nrf_wifi_drv_priv_zep {
struct nrf_wifi_fmac_priv *fmac_priv;
/* TODO: Replace with a linked list to handle unlimited RPUs */
struct nrf_wifi_ctx_zep rpu_ctx_zep;
};
extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
void nrf_wifi_scan_timeout_work(struct k_work *work);
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);
void configure_board_dep_params(struct nrf_wifi_board_params *board_params);
void set_tx_pwr_ceil_default(struct nrf_wifi_tx_pwr_ceil_params *pwr_ceil_params);
const char *nrf_wifi_get_drv_version(void);
enum nrf_wifi_status nrf_wifi_fmac_dev_add_zep(struct nrf_wifi_drv_priv_zep *drv_priv_zep);
enum nrf_wifi_status nrf_wifi_fmac_dev_rem_zep(struct nrf_wifi_drv_priv_zep *drv_priv_zep);
enum nrf_wifi_status nrf_wifi_fw_load(void *rpu_ctx);
struct nrf_wifi_vif_ctx_zep *nrf_wifi_get_vif_ctx(struct net_if *iface);
void nrf_wifi_rpu_recovery_cb(void *vif_ctx,
void *event_data,
unsigned int event_len);
#endif /* __ZEPHYR_FMAC_MAIN_H__ */

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing network stack interface specific declarations for
* the Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __ZEPHYR_NET_IF_H__
#define __ZEPHYR_NET_IF_H__
#include <zephyr/device.h>
#include <zephyr/net/net_pkt.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/ethernet.h>
#include <fmac_structs.h>
#include <zephyr/net/wifi_mgmt.h>
#define UNICAST_MASK GENMASK(7, 1)
#define LOCAL_BIT BIT(1)
void nrf_wifi_if_init_zep(struct net_if *iface);
int nrf_wifi_if_start_zep(const struct device *dev);
int nrf_wifi_if_stop_zep(const struct device *dev);
int nrf_wifi_if_set_config_zep(const struct device *dev,
enum ethernet_config_type type,
const struct ethernet_config *config);
int nrf_wifi_if_get_config_zep(const struct device *dev,
enum ethernet_config_type type,
struct ethernet_config *config);
enum ethernet_hw_caps nrf_wifi_if_caps_get(const struct device *dev);
int nrf_wifi_if_send(const struct device *dev,
struct net_pkt *pkt);
void nrf_wifi_if_rx_frm(void *os_vif_ctx,
void *frm);
#if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
void nrf_wifi_if_sniffer_rx_frm(void *os_vif_ctx,
void *frm,
struct raw_rx_pkt_header *raw_rx_hdr,
bool pkt_free);
#endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
enum nrf_wifi_status nrf_wifi_if_carr_state_chg(void *os_vif_ctx,
enum nrf_wifi_fmac_if_carr_state carr_state);
int nrf_wifi_stats_get(const struct device *dev,
struct net_stats_wifi *stats);
struct net_stats_eth *nrf_wifi_eth_stats_get(const struct device *dev);
void nrf_wifi_set_iface_event_handler(void *os_vif_ctx,
struct nrf_wifi_umac_event_set_interface *event,
unsigned int event_len);
#endif /* __ZEPHYR_NET_IF_H__ */

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing WiFi management operation implementations
* for the Zephyr OS.
*/
#ifndef __ZEPHYR_WIFI_MGMT_H__
#define __ZEPHYR_WIFI_MGMT_H__
#include <math.h>
#include <zephyr/device.h>
#include <zephyr/net/wifi_mgmt.h>
#include "osal_api.h"
/** Filter setting defines for sniffer mode. */
#define WIFI_MGMT_DATA_CTRL_FILTER_SETTING 0xE
#define WIFI_ALL_FILTER_SETTING 0xF
struct twt_interval_float {
unsigned short mantissa;
unsigned char exponent;
};
int nrf_wifi_set_power_save(const struct device *dev,
struct wifi_ps_params *params);
int nrf_wifi_set_twt(const struct device *dev,
struct wifi_twt_params *twt_params);
void nrf_wifi_event_proc_twt_setup_zep(void *vif_ctx,
struct nrf_wifi_umac_cmd_config_twt *twt_setup_info,
unsigned int event_len);
void nrf_wifi_event_proc_twt_teardown_zep(void *vif_ctx,
struct nrf_wifi_umac_cmd_teardown_twt *twt_teardown_info,
unsigned int event_len);
void nrf_wifi_event_proc_twt_sleep_zep(void *vif_ctx,
struct nrf_wifi_umac_event_twt_sleep *twt_sleep_info,
unsigned int event_len);
int nrf_wifi_twt_teardown_flows(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep,
unsigned char start_flow_id, unsigned char end_flow_id);
int nrf_wifi_get_power_save_config(const struct device *dev,
struct wifi_ps_config *ps_config);
void nrf_wifi_event_proc_get_power_save_info(void *vif_ctx,
struct nrf_wifi_umac_event_power_save_info *ps_info,
unsigned int event_len);
#ifdef CONFIG_NRF70_SYSTEM_WITH_RAW_MODES
int nrf_wifi_mode(const struct device *dev,
struct wifi_mode_info *mode);
#endif
#if defined(CONFIG_NRF70_RAW_DATA_TX) || defined(CONFIG_NRF70_RAW_DATA_RX)
int nrf_wifi_channel(const struct device *dev,
struct wifi_channel_info *channel);
#endif /* CONFIG_NRF70_RAW_DATA_TX || CONFIG_NRF70_RAW_DATA_RX */
#if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
int nrf_wifi_filter(const struct device *dev,
struct wifi_filter_info *filter);
#endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
int nrf_wifi_set_rts_threshold(const struct device *dev,
unsigned int rts_threshold);
#endif /* __ZEPHYR_WIFI_MGMT_H__ */

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing display scan specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __ZEPHYR_DISP_SCAN_H__
#define __ZEPHYR_DISP_SCAN_H__
#include <zephyr/device.h>
#include <zephyr/net/wifi_mgmt.h>
#include "osal_api.h"
int nrf_wifi_disp_scan_zep(const struct device *dev, struct wifi_scan_params *params,
scan_result_cb_t cb);
enum nrf_wifi_status nrf_wifi_disp_scan_res_get_zep(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep);
void nrf_wifi_event_proc_disp_scan_res_zep(void *vif_ctx,
struct nrf_wifi_umac_event_new_scan_display_results *scan_res,
unsigned int event_len,
bool is_last);
#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS
void nrf_wifi_rx_bcn_prb_resp_frm(void *vif_ctx,
void *frm,
unsigned short frequency,
signed short signal);
#endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */
#endif /* __ZEPHYR_DISP_SCAN_H__ */

View file

@ -0,0 +1,143 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing WPA supplicant interface specific declarations for
* the Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __ZEPHYR_WPA_SUPP_IF_H__
#define __ZEPHYR_WPA_SUPP_IF_H__
#define RPU_RESP_EVENT_TIMEOUT 5000
#ifdef CONFIG_NRF70_STA_MODE
#include <drivers/driver_zephyr.h>
void *nrf_wifi_wpa_supp_dev_init(void *supp_drv_if_ctx, const char *iface_name,
struct zep_wpa_supp_dev_callbk_fns *supp_callbk_fns);
void nrf_wifi_wpa_supp_dev_deinit(void *if_priv);
int nrf_wifi_wpa_supp_scan2(void *if_priv, struct wpa_driver_scan_params *params);
int nrf_wifi_wpa_supp_scan_abort(void *if_priv);
int nrf_wifi_wpa_supp_scan_results_get(void *if_priv);
int nrf_wifi_wpa_supp_deauthenticate(void *if_priv, const char *addr, unsigned short reason_code);
int nrf_wifi_wpa_supp_authenticate(void *if_priv, struct wpa_driver_auth_params *params,
struct wpa_bss *curr_bss);
int nrf_wifi_wpa_supp_associate(void *if_priv, struct wpa_driver_associate_params *params);
int nrf_wifi_wpa_set_supp_port(void *if_priv, int authorized, char *bssid);
int nrf_wifi_wpa_supp_signal_poll(void *if_priv, struct wpa_signal_info *si,
unsigned char *bssid);
int nrf_wifi_nl80211_send_mlme(void *if_priv, const u8 *data, size_t data_len, int noack,
unsigned int freq, int no_cck, int offchanok, unsigned int wait_time,
int cookie);
int nrf_wifi_supp_get_wiphy(void *if_priv);
int nrf_wifi_supp_register_frame(void *if_priv,
u16 type, const u8 *match, size_t match_len,
bool multicast);
int nrf_wifi_wpa_supp_set_key(void *if_priv,
const unsigned char *ifname,
enum wpa_alg alg,
const unsigned char *addr,
int key_idx,
int set_tx,
const unsigned char *seq,
size_t seq_len,
const unsigned char *key,
size_t key_len,
enum key_flag key_flag);
void nrf_wifi_wpa_supp_event_proc_scan_start(void *if_priv);
void nrf_wifi_wpa_supp_event_proc_scan_done(void *if_priv,
struct nrf_wifi_umac_event_trigger_scan *scan_done_event,
unsigned int event_len,
int aborted);
void nrf_wifi_wpa_supp_event_proc_scan_res(void *if_priv,
struct nrf_wifi_umac_event_new_scan_results *scan_res,
unsigned int event_len,
bool more_res);
void nrf_wifi_wpa_supp_event_proc_auth_resp(void *if_priv,
struct nrf_wifi_umac_event_mlme *auth_resp,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_proc_assoc_resp(void *if_priv,
struct nrf_wifi_umac_event_mlme *assoc_resp,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_proc_deauth(void *if_priv,
struct nrf_wifi_umac_event_mlme *deauth,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_proc_disassoc(void *if_priv,
struct nrf_wifi_umac_event_mlme *disassoc,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_proc_get_sta(void *if_priv,
struct nrf_wifi_umac_event_new_station *info,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_proc_get_if(void *if_priv,
struct nrf_wifi_interface_info *info,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_mgmt_tx_status(void *if_priv,
struct nrf_wifi_umac_event_mlme *mlme_event,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_proc_unprot_mgmt(void *if_priv,
struct nrf_wifi_umac_event_mlme *unprot_mgmt,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_get_wiphy(void *if_priv,
struct nrf_wifi_event_get_wiphy *get_wiphy,
unsigned int event_len);
void nrf_wifi_wpa_supp_event_mgmt_rx_callbk_fn(void *if_priv,
struct nrf_wifi_umac_event_mlme *mgmt_rx_event,
unsigned int event_len);
int nrf_wifi_supp_get_capa(void *if_priv, struct wpa_driver_capa *capa);
void nrf_wifi_wpa_supp_event_mac_chgd(void *if_priv);
int nrf_wifi_supp_get_conn_info(void *if_priv, struct wpa_conn_info *info);
void nrf_wifi_supp_event_proc_get_conn_info(void *os_vif_ctx,
struct nrf_wifi_umac_event_conn_info *info,
unsigned int event_len);
#endif /* CONFIG_NRF70_STA_MODE */
#ifdef CONFIG_NRF70_AP_MODE
int nrf_wifi_wpa_supp_init_ap(void *if_priv, struct wpa_driver_associate_params *params);
int nrf_wifi_wpa_supp_start_ap(void *if_priv, struct wpa_driver_ap_params *params);
int nrf_wifi_wpa_supp_change_beacon(void *if_priv, struct wpa_driver_ap_params *params);
int nrf_wifi_wpa_supp_stop_ap(void *if_priv);
int nrf_wifi_wpa_supp_deinit_ap(void *if_priv);
int nrf_wifi_wpa_supp_sta_add(void *if_priv, struct hostapd_sta_add_params *params);
int nrf_wifi_wpa_supp_sta_remove(void *if_priv, const u8 *addr);
int nrf_wifi_supp_register_mgmt_frame(void *if_priv,
u16 frame_type, size_t match_len, const u8 *match);
int nrf_wifi_wpa_supp_sta_set_flags(void *if_priv, const u8 *addr,
unsigned int total_flags, unsigned int flags_or,
unsigned int flags_and);
int nrf_wifi_wpa_supp_sta_get_inact_sec(void *if_priv, const u8 *addr);
#endif /* CONFIG_NRF70_AP_MODE */
#endif /* __ZEPHYR_WPA_SUPP_IF_H__ */

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Custom Linker command/script file
*
* Custom Linker script for the Cortex-M platforms.
*/
#include <zephyr/linker/sections.h>
#include <zephyr/devicetree.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/linker/linker-tool.h>
#if CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP || CONFIG_BOARD_NRF52840DK_NRF52840
/*
* nRF53/52 series ship an external flash that can be used for XIP using QSPI/SPI.
*
* Note: In nRF7002 external flash using is accessible only using SPI but there is no
* support for XIP, so, relocation cannot be used.
*/
#if CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP
#define EXTFLASH_BASE_ADDR 0x10000000
#define EXTFLASH_SIZE 0x800000
#elif CONFIG_BOARD_NRF52840DK_NRF52840
#define EXTFLASH_BASE_ADDR 0x12000000
#define EXTFLASH_SIZE 0x800000
#endif /* CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP */
#if USE_PARTITION_MANAGER && PM_EXTERNAL_FLASH_ADDRESS
#include <pm_config.h>
#define EXTFLASH_ADDRESS (EXTFLASH_BASE_ADDR + PM_EXTERNAL_FLASH_ADDRESS)
#undef EXTFLASH_SIZE
#define EXTFLASH_SIZE (PM_EXTERNAL_FLASH_SIZE)
#else
#define EXTFLASH_ADDRESS (EXTFLASH_BASE_ADDR)
#endif /* USE_PARTITION_MANAGER && PM_EXTERNAL_FLASH_ADDRESS */
MEMORY
{
EXTFLASH (wx) : ORIGIN = EXTFLASH_ADDRESS, LENGTH = EXTFLASH_SIZE
}
#endif /* CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP || CONFIG_BOARD_NRF52840DK_NRF52840 */
#include <zephyr/arch/arm/cortex_m/scripts/linker.ld>

View file

@ -0,0 +1,333 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
* @brief Coexistence functions
*/
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/gpio.h>
#include "coex.h"
#include "coex_struct.h"
#include "fmac_main.h"
#include "fmac_api.h"
LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
static struct nrf_wifi_ctx_zep *rpu_ctx = &rpu_drv_priv_zep.rpu_ctx_zep;
#define CH_BASE_ADDRESS ABS_EXT_SYS_WLANSYSCOEX_CH_CONTROL
#define COEX_CONFIG_FIXED_PARAMS 4
#define COEX_REG_CFG_OFFSET_SHIFT 24
/* copied from uccp530_77_registers_ext_sys_bus.h of UCCP toolkit */
#define EXT_SYS_WLANSYSCOEX_CH_CONTROL 0x0000
#define ABS_EXT_SYS_WLANSYSCOEX_CH_CONTROL 0xA401BC00UL
#define EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE 0x0004
#define EXT_SYS_WLANSYSCOEX_CH_SR_INFO_STATUS 0x0040
#define EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0 0x008C
#define EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_44 0x013C
#define EXT_SYS_WLANSYSCOEX_RESET_SHIFT 0
/* copied from uccp530_77_registers.h of UCCP toolkit */
#define ABS_PMB_WLAN_MAC_CTRL_PULSED_SOFTWARE_RESET 0xA5009A00UL
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
#define NRF_RADIO_COEX_NODE DT_NODELABEL(nrf70)
static const struct gpio_dt_spec sr_rf_switch_spec =
GPIO_DT_SPEC_GET(NRF_RADIO_COEX_NODE, srrf_switch_gpios);
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
/* PTA registers configuration of Coexistence Hardware */
/* Separate antenna configuration, WLAN in 2.4GHz. For BLE protocol. */
const uint16_t config_buffer_SEA_ble[] = {
0x0019, 0x00F6, 0x0008, 0x0062, 0x00F5,
0x00F5, 0x0019, 0x0019, 0x0074, 0x0074,
0x0008, 0x01E2, 0x00D5, 0x00D5, 0x01F6,
0x01F6, 0x0061, 0x0061, 0x01E2, 0x0008,
0x0004, 0x0004, 0x0019, 0x0019, 0x0008,
0x0008, 0x00F5, 0x00F5, 0x00D5, 0x00D5,
0x0008, 0x01E2, 0x0051, 0x0051, 0x0074,
0x0074, 0x00F6, 0x0019, 0x0062, 0x0019,
0x00F6, 0x0008, 0x0062, 0x0008, 0x001A
};
/* Separate antenna configuration, WLAN in 2.4GHz. For non BLE protocol */
const uint16_t config_buffer_SEA_non_ble[] = {
0x0019, 0x00F6, 0x0008, 0x0062, 0x00F5,
0x00F5, 0x0061, 0x0061, 0x0074, 0x0074,
0x01E2, 0x01E2, 0x00D5, 0x00D5, 0x01F6,
0x01F6, 0x0061, 0x0061, 0x01E2, 0x01E2,
0x00C4, 0x00C4, 0x0061, 0x0061, 0x0008,
0x0008, 0x00F5, 0x00F5, 0x00D5, 0x00D5,
0x0162, 0x0162, 0x0019, 0x0019, 0x01F6,
0x01F6, 0x00F6, 0x0019, 0x0062, 0x0019,
0x00F6, 0x0008, 0x0062, 0x0008, 0x001A
};
/* Shared antenna configuration, WLAN in 2.4GHz. */
const uint16_t config_buffer_SHA[] = {
0x0019, 0x00F6, 0x0008, 0x00E2, 0x0015,
0x00F5, 0x0019, 0x0019, 0x0004, 0x01F6,
0x0008, 0x01E2, 0x00F5, 0x00F5, 0x01F6,
0x01F6, 0x00E1, 0x00E1, 0x01E2, 0x0008,
0x0004, 0x0004, 0x0019, 0x0019, 0x0008,
0x0008, 0x0015, 0x00F5, 0x00F5, 0x00F5,
0x0008, 0x01E2, 0x00E1, 0x00E1, 0x0004,
0x01F6, 0x00F6, 0x0019, 0x00E2, 0x0019,
0x00F6, 0x0008, 0x00E2, 0x0008, 0x001A
};
/* Shared/separate antennas, WLAN in 5GHz */
const uint16_t config_buffer_5G[] = {
0x0039, 0x0076, 0x0028, 0x0062, 0x0075,
0x0075, 0x0061, 0x0061, 0x0074, 0x0074,
0x0060, 0x0060, 0x0075, 0x0075, 0x0064,
0x0064, 0x0071, 0x0071, 0x0060, 0x0060,
0x0064, 0x0064, 0x0061, 0x0061, 0x0060,
0x0060, 0x0075, 0x0075, 0x0075, 0x0075,
0x0060, 0x0060, 0x0071, 0x0071, 0x0074,
0x0074, 0x0076, 0x0039, 0x0062, 0x0039,
0x0076, 0x0028, 0x0062, 0x0028, 0x003A
};
/* non-PTA register configuration of coexistence hardware */
/* Shared antenna */
const uint32_t ch_config_sha[] = {
0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
0x00000000, 0x00000021, 0x000002ca, 0x00000050, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000
};
/* Separate antennas. For BLE protocol. */
const uint32_t ch_config_sep_ble[] = {
0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
0x00000000, 0x00000021, 0x000002ca, 0x00000055, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000
};
/* Separate antennas. For non BLE protocol. */
const uint32_t ch_config_sep_non_ble[] = {
0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
0x00000000, 0x00000021, 0x000002ca, 0x00000055, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000
};
int nrf_wifi_coex_config_non_pta(bool separate_antennas, bool is_sr_protocol_ble)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct coex_ch_configuration params = { 0 };
const uint32_t *config_buffer_ptr = NULL;
uint32_t start_offset = 0;
uint32_t num_reg_to_config = 1;
uint32_t cmd_len, index;
/* Offset from the base address of CH */
start_offset = ((EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE -
EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
/* Number of registers to be configured */
num_reg_to_config = ((EXT_SYS_WLANSYSCOEX_CH_SR_INFO_STATUS -
EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE) >> 2) + 1;
if (separate_antennas) {
if (is_sr_protocol_ble) {
config_buffer_ptr = ch_config_sep_ble;
} else {
config_buffer_ptr = ch_config_sep_non_ble;
}
} else {
config_buffer_ptr = ch_config_sha;
}
params.message_id = HW_CONFIGURATION;
params.num_reg_to_config = num_reg_to_config;
params.hw_to_config = COEX_HARDWARE;
params.hw_block_base_addr = CH_BASE_ADDRESS;
for (index = 0; index < num_reg_to_config; index++) {
params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
(*(config_buffer_ptr + index));
start_offset++;
}
cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
(void *)(&params), cmd_len);
if (status != NRF_WIFI_STATUS_SUCCESS) {
return -1;
}
return 0;
}
int nrf_wifi_coex_config_pta(enum nrf_wifi_pta_wlan_op_band wlan_band, bool separate_antennas,
bool is_sr_protocol_ble)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct coex_ch_configuration params = { 0 };
const uint16_t *config_buffer_ptr = NULL;
uint32_t start_offset = 0;
uint32_t num_reg_to_config = 1;
uint32_t cmd_len, index;
/* common for both SHA and SEA */
/* Indicates offset from the base address of CH */
start_offset = ((EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0 -
EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
/* Number of contiguous registers to be configured starting from base+offset */
num_reg_to_config = ((EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_44 -
EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0) >> 2) + 1;
if (wlan_band == NRF_WIFI_PTA_WLAN_OP_BAND_2_4_GHZ) {
/* WLAN operating in 2.4GHz */
if (separate_antennas) {
/* separate antennas configuration */
if (is_sr_protocol_ble) {
config_buffer_ptr = config_buffer_SEA_ble;
} else {
config_buffer_ptr = config_buffer_SEA_non_ble;
}
} else {
/* Shared antenna configuration */
config_buffer_ptr = config_buffer_SHA;
}
} else if (wlan_band == NRF_WIFI_PTA_WLAN_OP_BAND_5_GHZ) {
/* WLAN operating in 5GHz */
config_buffer_ptr = config_buffer_5G;
} else {
return -EINVAL;
}
params.message_id = HW_CONFIGURATION;
params.num_reg_to_config = num_reg_to_config;
params.hw_to_config = COEX_HARDWARE;
params.hw_block_base_addr = CH_BASE_ADDRESS;
for (index = 0; index < num_reg_to_config; index++) {
params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
(*(config_buffer_ptr+index));
start_offset++;
}
cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
(void *)(&params), cmd_len);
if (status != NRF_WIFI_STATUS_SUCCESS) {
return -1;
}
return 0;
}
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
int nrf_wifi_config_sr_switch(bool separate_antennas)
{
int ret;
if (!device_is_ready(sr_rf_switch_spec.port)) {
LOG_ERR("Unable to open GPIO device");
return -ENODEV;
}
ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_OUTPUT);
if (ret < 0) {
LOG_ERR("Unable to configure GPIO device");
return -1;
}
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;
}
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
int nrf_wifi_coex_hw_reset(void)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct coex_ch_configuration params = { 0 };
uint32_t num_reg_to_config = 1;
uint32_t start_offset = 0;
uint32_t index = 0;
uint32_t coex_hw_reset = 1;
uint32_t cmd_len;
/* reset CH */
params.message_id = HW_CONFIGURATION;
params.num_reg_to_config = num_reg_to_config;
params.hw_to_config = COEX_HARDWARE;
params.hw_block_base_addr = CH_BASE_ADDRESS;
start_offset = ((EXT_SYS_WLANSYSCOEX_CH_CONTROL - EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
(coex_hw_reset << EXT_SYS_WLANSYSCOEX_RESET_SHIFT);
cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
(void *)(&params), cmd_len);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("CH reset configuration failed");
return -1;
}
return 0;
}
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
int sr_gpio_config(void)
{
int ret;
if (!device_is_ready(sr_rf_switch_spec.port)) {
return -ENODEV;
}
ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_OUTPUT);
if (ret) {
LOG_ERR("SR GPIO configuration failed %d", ret);
}
return ret;
}
int sr_gpio_remove(void)
{
int ret;
ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_DISCONNECTED);
if (ret) {
LOG_ERR("SR GPIO remove failed %d", ret);
}
return ret;
}
int sr_ant_switch(unsigned int ant_switch)
{
int ret;
ret = gpio_pin_set_dt(&sr_rf_switch_spec, ant_switch & 0x1);
if (ret) {
LOG_ERR("SR GPIO set failed %d", ret);
}
return ret;
}
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */

View file

@ -0,0 +1,933 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing FMAC interface specific definitions for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#include <stdlib.h>
#include <zephyr/kernel.h>
#ifdef CONFIG_NET_L2_ETHERNET
#include <zephyr/net/ethernet.h>
#endif
#include <zephyr/logging/log.h>
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/conn_mgr_connectivity.h>
#include <zephyr/net/conn_mgr_connectivity_impl.h>
#include <util.h>
#include <fmac_api.h>
#include "fmac_util.h"
#include <fmac_main.h>
#ifndef CONFIG_NRF70_RADIO_TEST
#ifdef CONFIG_NRF70_STA_MODE
#include <zephyr/net/wifi_nm.h>
#include <wifi_mgmt_scan.h>
#include <wifi_mgmt.h>
#include <wpa_supp_if.h>
#else
#include <wifi_mgmt.h>
#include <wifi_mgmt_scan.h>
#endif /* CONFIG_NRF70_STA_MODE */
#include <zephyr/net/conn_mgr_connectivity.h>
#endif /* !CONFIG_NRF70_RADIO_TEST */
#define DT_DRV_COMPAT nordic_wlan
LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
/* 3 bytes for addreess, 3 bytes for length */
#define MAX_PKT_RAM_TX_ALIGN_OVERHEAD 6
#ifndef CONFIG_NRF70_RADIO_TEST
#ifdef CONFIG_NRF70_DATA_TX
#define MAX_RX_QUEUES 3
#define MAX_TX_FRAME_SIZE \
(CONFIG_NRF_WIFI_IFACE_MTU + NRF_WIFI_FMAC_ETH_HDR_LEN + TX_BUF_HEADROOM)
#define TOTAL_TX_SIZE \
(CONFIG_NRF70_MAX_TX_TOKENS * CONFIG_NRF70_TX_MAX_DATA_SIZE)
#define TOTAL_RX_SIZE \
(CONFIG_NRF70_RX_NUM_BUFS * CONFIG_NRF70_RX_MAX_DATA_SIZE)
BUILD_ASSERT(CONFIG_NRF70_MAX_TX_TOKENS >= 1,
"At least one TX token is required");
BUILD_ASSERT(CONFIG_NRF70_MAX_TX_AGGREGATION <= 15,
"Max TX aggregation is 15");
BUILD_ASSERT(CONFIG_NRF70_RX_NUM_BUFS >= 1,
"At least one RX buffer is required");
BUILD_ASSERT(RPU_PKTRAM_SIZE - TOTAL_RX_SIZE >= TOTAL_TX_SIZE,
"Packet RAM overflow: not enough memory for TX");
BUILD_ASSERT(CONFIG_NRF70_TX_MAX_DATA_SIZE >= MAX_TX_FRAME_SIZE,
"TX buffer size must be at least as big as the MTU and headroom");
static const unsigned char aggregation = 1;
static const unsigned char wmm = 1;
static const unsigned char max_num_tx_agg_sessions = 4;
static const unsigned char max_num_rx_agg_sessions = 8;
static const unsigned char reorder_buf_size = 16;
static const unsigned char max_rxampdu_size = MAX_RX_AMPDU_SIZE_64KB;
static const unsigned char max_tx_aggregation = CONFIG_NRF70_MAX_TX_AGGREGATION;
static const unsigned int rx1_num_bufs = CONFIG_NRF70_RX_NUM_BUFS / MAX_RX_QUEUES;
static const unsigned int rx2_num_bufs = CONFIG_NRF70_RX_NUM_BUFS / MAX_RX_QUEUES;
static const unsigned int rx3_num_bufs = CONFIG_NRF70_RX_NUM_BUFS / MAX_RX_QUEUES;
static const unsigned int rx1_buf_sz = CONFIG_NRF70_RX_MAX_DATA_SIZE;
static const unsigned int rx2_buf_sz = CONFIG_NRF70_RX_MAX_DATA_SIZE;
static const unsigned int rx3_buf_sz = CONFIG_NRF70_RX_MAX_DATA_SIZE;
static const unsigned char rate_protection_type;
#else
/* Reduce buffers to Scan only operation */
static const unsigned int rx1_num_bufs = 2;
static const unsigned int rx2_num_bufs = 2;
static const unsigned int rx3_num_bufs = 2;
static const unsigned int rx1_buf_sz = 1000;
static const unsigned int rx2_buf_sz = 1000;
static const unsigned int rx3_buf_sz = 1000;
#endif
struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
static K_MUTEX_DEFINE(reg_lock);
const char *nrf_wifi_get_drv_version(void)
{
return NRF70_DRIVER_VERSION;
}
/* If the interface is not Wi-Fi then errors are expected, so, fail silently */
struct nrf_wifi_vif_ctx_zep *nrf_wifi_get_vif_ctx(struct net_if *iface)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct nrf_wifi_ctx_zep *rpu_ctx = &rpu_drv_priv_zep.rpu_ctx_zep;
if (!iface || !rpu_ctx || !rpu_ctx->rpu_ctx) {
return NULL;
}
for (int i = 0; i < ARRAY_SIZE(rpu_ctx->vif_ctx_zep); i++) {
if (rpu_ctx->vif_ctx_zep[i].zep_net_if_ctx == iface) {
vif_ctx_zep = &rpu_ctx->vif_ctx_zep[i];
break;
}
}
return vif_ctx_zep;
}
void nrf_wifi_event_proc_scan_start_zep(void *if_priv,
struct nrf_wifi_umac_event_trigger_scan *scan_start_event,
unsigned int event_len)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
vif_ctx_zep = if_priv;
if (vif_ctx_zep->scan_type == SCAN_DISPLAY) {
return;
}
#ifdef CONFIG_NRF70_STA_MODE
nrf_wifi_wpa_supp_event_proc_scan_start(if_priv);
#endif /* CONFIG_NRF70_STA_MODE */
}
void nrf_wifi_event_proc_scan_done_zep(void *vif_ctx,
struct nrf_wifi_umac_event_trigger_scan *scan_done_event,
unsigned int event_len)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
vif_ctx_zep = vif_ctx;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
return;
}
switch (vif_ctx_zep->scan_type) {
#ifdef CONFIG_NET_L2_WIFI_MGMT
case SCAN_DISPLAY:
status = nrf_wifi_disp_scan_res_get_zep(vif_ctx_zep);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: nrf_wifi_disp_scan_res_get_zep failed", __func__);
return;
}
vif_ctx_zep->scan_in_progress = false;
break;
#endif /* CONFIG_NET_L2_WIFI_MGMT */
#ifdef CONFIG_NRF70_STA_MODE
case SCAN_CONNECT:
nrf_wifi_wpa_supp_event_proc_scan_done(vif_ctx_zep,
scan_done_event,
event_len,
0);
break;
#endif /* CONFIG_NRF70_STA_MODE */
default:
LOG_ERR("%s: Scan type = %d not supported yet", __func__, vif_ctx_zep->scan_type);
return;
}
status = NRF_WIFI_STATUS_SUCCESS;
}
void nrf_wifi_scan_timeout_work(struct k_work *work)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
vif_ctx_zep = CONTAINER_OF(work, struct nrf_wifi_vif_ctx_zep, scan_timeout_work.work);
if (!vif_ctx_zep->scan_in_progress) {
LOG_INF("%s: Scan not in progress", __func__);
return;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
#ifdef CONFIG_NET_L2_WIFI_MGMT
if (vif_ctx_zep->disp_scan_cb) {
vif_ctx_zep->disp_scan_cb(vif_ctx_zep->zep_net_if_ctx, -ETIMEDOUT, NULL);
vif_ctx_zep->disp_scan_cb = NULL;
} else
#endif /* CONFIG_NET_L2_WIFI_MGMT */
{
#ifdef CONFIG_NRF70_STA_MODE
/* WPA supplicant scan */
union wpa_event_data event;
struct scan_info *info = NULL;
memset(&event, 0, sizeof(event));
info = &event.scan_info;
info->aborted = 0;
info->external_scan = 0;
info->nl_scan_event = 1;
if (vif_ctx_zep->supp_drv_if_ctx &&
vif_ctx_zep->supp_callbk_fns.scan_done) {
vif_ctx_zep->supp_callbk_fns.scan_done(vif_ctx_zep->supp_drv_if_ctx,
&event);
}
#endif /* CONFIG_NRF70_STA_MODE */
}
vif_ctx_zep->scan_in_progress = false;
}
#ifdef CONFIG_NRF70_STA_MODE
static void nrf_wifi_process_rssi_from_rx(void *vif_ctx,
signed short signal)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = vif_ctx;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
vif_ctx_zep = vif_ctx;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
return;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
if (!rpu_ctx_zep) {
LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
return;
}
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
vif_ctx_zep->rssi = MBM_TO_DBM(signal);
vif_ctx_zep->rssi_record_timestamp_us =
nrf_wifi_osal_time_get_curr_us(fmac_dev_ctx->fpriv->opriv);
}
#endif /* CONFIG_NRF70_STA_MODE */
void nrf_wifi_event_get_reg_zep(void *vif_ctx,
struct nrf_wifi_reg *get_reg_event,
unsigned int event_len)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
LOG_DBG("%s: alpha2 = %c%c", __func__,
get_reg_event->nrf_wifi_alpha2[0],
get_reg_event->nrf_wifi_alpha2[1]);
vif_ctx_zep = vif_ctx;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
return;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
if (fmac_dev_ctx->alpha2_valid) {
LOG_ERR("%s: Unsolicited regulatory get!", __func__);
return;
}
memcpy(&fmac_dev_ctx->alpha2,
&get_reg_event->nrf_wifi_alpha2,
sizeof(get_reg_event->nrf_wifi_alpha2));
fmac_dev_ctx->reg_chan_count = get_reg_event->num_channels;
memcpy(fmac_dev_ctx->reg_chan_info,
&get_reg_event->chn_info,
fmac_dev_ctx->reg_chan_count *
sizeof(struct nrf_wifi_get_reg_chn_info));
fmac_dev_ctx->alpha2_valid = true;
}
int nrf_wifi_reg_domain(const struct device *dev, struct wifi_reg_domain *reg_domain)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct nrf_wifi_fmac_reg_info reg_domain_info = {0};
struct wifi_reg_chan_info *chan_info = NULL;
struct nrf_wifi_get_reg_chn_info *reg_domain_chan_info = NULL;
int ret = -1;
int chan_idx = 0;
k_mutex_lock(&reg_lock, K_FOREVER);
if (!dev || !reg_domain) {
goto err;
}
vif_ctx_zep = dev->data;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
goto err;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
if (!rpu_ctx_zep) {
LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
goto err;
}
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
if (!fmac_dev_ctx) {
LOG_ERR("%s: fmac_dev_ctx is NULL", __func__);
goto err;
}
if (reg_domain->oper == WIFI_MGMT_SET) {
#ifndef CONFIG_NRF70_RADIO_TEST
#ifdef CONFIG_NRF70_STA_MODE
/* Need to check if WPA supplicant is initialized or not.
* Must be checked when CONFIG_WIFI_NM_WPA_SUPPLICANT is enabled.
* Not applicable for RADIO_TEST or when
* CONFIG_WIFI_NM_WPA_SUPPLICANT is not enabled.
*/
/* It is possbile that during supplicant initialization driver may
* get the command. lock will try to ensure that supplicant
* initialization is complete.
*/
k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
if ((!vif_ctx_zep->supp_drv_if_ctx) ||
(!wifi_nm_get_instance_iface(vif_ctx_zep->zep_net_if_ctx))) {
LOG_ERR("%s: WPA supplicant initialization not complete yet", __func__);
k_mutex_unlock(&vif_ctx_zep->vif_lock);
goto err;
}
k_mutex_unlock(&vif_ctx_zep->vif_lock);
#endif /* CONFIG_NRF70_STA_MODE */
#endif /* !CONFIG_NRF70_RADIO_TEST */
memcpy(reg_domain_info.alpha2, reg_domain->country_code, WIFI_COUNTRY_CODE_LEN);
reg_domain_info.force = reg_domain->force;
status = nrf_wifi_fmac_set_reg(fmac_dev_ctx, &reg_domain_info);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: Failed to set regulatory domain", __func__);
goto err;
}
} else if (reg_domain->oper == WIFI_MGMT_GET) {
if (!reg_domain->chan_info) {
LOG_ERR("%s: Invalid regulatory info (NULL)\n", __func__);
goto err;
}
status = nrf_wifi_fmac_get_reg(fmac_dev_ctx, &reg_domain_info);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: Failed to get regulatory domain", __func__);
goto err;
}
memcpy(reg_domain->country_code, reg_domain_info.alpha2, WIFI_COUNTRY_CODE_LEN);
reg_domain->num_channels = reg_domain_info.reg_chan_count;
for (chan_idx = 0; chan_idx < reg_domain_info.reg_chan_count; chan_idx++) {
chan_info = &(reg_domain->chan_info[chan_idx]);
reg_domain_chan_info = &(reg_domain_info.reg_chan_info[chan_idx]);
chan_info->center_frequency = reg_domain_chan_info->center_frequency;
chan_info->dfs = !!reg_domain_chan_info->dfs;
chan_info->max_power = reg_domain_chan_info->max_power;
chan_info->passive_only = !!reg_domain_chan_info->passive_channel;
chan_info->supported = !!reg_domain_chan_info->supported;
}
} else {
LOG_ERR("%s: Invalid operation: %d", __func__, reg_domain->oper);
goto err;
}
ret = 0;
err:
k_mutex_unlock(&reg_lock);
return ret;
}
#ifdef CONFIG_NRF70_STA_MODE
void nrf_wifi_event_proc_cookie_rsp(void *vif_ctx,
struct nrf_wifi_umac_event_cookie_rsp *cookie_rsp_event,
unsigned int event_len)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
vif_ctx_zep = vif_ctx;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
return;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
LOG_DBG("%s: cookie_rsp_event->cookie = %llx", __func__, cookie_rsp_event->cookie);
LOG_DBG("%s: host_cookie = %llx", __func__, cookie_rsp_event->host_cookie);
LOG_DBG("%s: mac_addr = %x:%x:%x:%x:%x:%x", __func__,
cookie_rsp_event->mac_addr[0],
cookie_rsp_event->mac_addr[1],
cookie_rsp_event->mac_addr[2],
cookie_rsp_event->mac_addr[3],
cookie_rsp_event->mac_addr[4],
cookie_rsp_event->mac_addr[5]);
vif_ctx_zep->cookie_resp_received = true;
/* TODO: When supp_callbk_fns.mgmt_tx_status is implemented, add logic
* here to use the cookie and host_cookie to map requests to responses.
*/
}
#endif /* CONFIG_NRF70_STA_MODE */
void reg_change_callbk_fn(void *vif_ctx,
struct nrf_wifi_event_regulatory_change *reg_change_event,
unsigned int event_len)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
vif_ctx_zep = vif_ctx;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
return;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
if (!rpu_ctx_zep) {
LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
return;
}
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
if (!fmac_dev_ctx) {
LOG_ERR("%s: fmac_dev_ctx is NULL", __func__);
return;
}
fmac_dev_ctx->reg_change = k_malloc(sizeof(struct nrf_wifi_event_regulatory_change));
if (!fmac_dev_ctx->reg_change) {
LOG_ERR("%s: Failed to allocate memory for reg_change", __func__);
return;
}
memcpy(fmac_dev_ctx->reg_change,
reg_change_event,
sizeof(struct nrf_wifi_event_regulatory_change));
fmac_dev_ctx->reg_set_status = true;
}
#endif /* !CONFIG_NRF70_RADIO_TEST */
/* 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
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)
{
tx_pwr_ctrl_params->ant_gain_2g = CONFIG_NRF70_ANT_GAIN_2G;
tx_pwr_ctrl_params->ant_gain_5g_band1 = CONFIG_NRF70_ANT_GAIN_5G_BAND1;
tx_pwr_ctrl_params->ant_gain_5g_band2 = CONFIG_NRF70_ANT_GAIN_5G_BAND2;
tx_pwr_ctrl_params->ant_gain_5g_band3 = CONFIG_NRF70_ANT_GAIN_5G_BAND3;
tx_pwr_ctrl_params->band_edge_2g_lo_dss = CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_DSSS;
tx_pwr_ctrl_params->band_edge_2g_lo_ht = CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_2g_lo_he = CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_2g_hi_dsss = CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_DSSS;
tx_pwr_ctrl_params->band_edge_2g_hi_ht = CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_2g_hi_he = CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_1_lo_ht =
CONFIG_NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_1_lo_he =
CONFIG_NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_1_hi_ht =
CONFIG_NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_1_hi_he =
CONFIG_NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_2a_lo_ht =
CONFIG_NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_2a_lo_he =
CONFIG_NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_2a_hi_ht =
CONFIG_NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_2a_hi_he =
CONFIG_NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_2c_lo_ht =
CONFIG_NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_2c_lo_he =
CONFIG_NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_2c_hi_ht =
CONFIG_NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_2c_hi_he =
CONFIG_NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_3_lo_ht =
CONFIG_NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_3_lo_he =
CONFIG_NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_3_hi_ht =
CONFIG_NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_3_hi_he =
CONFIG_NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_4_lo_ht =
CONFIG_NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_4_lo_he =
CONFIG_NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HE;
tx_pwr_ctrl_params->band_edge_5g_unii_4_hi_ht =
CONFIG_NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HT;
tx_pwr_ctrl_params->band_edge_5g_unii_4_hi_he =
CONFIG_NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HE;
tx_pwr_ceil_params->max_pwr_2g_dsss = MAX_TX_PWR(wifi_max_tx_pwr_2g_dsss);
tx_pwr_ceil_params->max_pwr_2g_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_2g_mcs7);
tx_pwr_ceil_params->max_pwr_2g_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_2g_mcs0);
#ifndef CONFIG_NRF70_2_4G_ONLY
tx_pwr_ceil_params->max_pwr_5g_low_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_5g_low_mcs7);
tx_pwr_ceil_params->max_pwr_5g_mid_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_5g_mid_mcs7);
tx_pwr_ceil_params->max_pwr_5g_high_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_5g_high_mcs7);
tx_pwr_ceil_params->max_pwr_5g_low_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_5g_low_mcs0);
tx_pwr_ceil_params->max_pwr_5g_mid_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_5g_mid_mcs0);
tx_pwr_ceil_params->max_pwr_5g_high_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_5g_high_mcs0);
#endif /* CONFIG_NRF70_2_4G_ONLY */
}
void configure_board_dep_params(struct nrf_wifi_board_params *board_params)
{
board_params->pcb_loss_2g = CONFIG_NRF70_PCB_LOSS_2G;
#ifndef CONFIG_NRF70_2_4G_ONLY
board_params->pcb_loss_5g_band1 = CONFIG_NRF70_PCB_LOSS_5G_BAND1;
board_params->pcb_loss_5g_band2 = CONFIG_NRF70_PCB_LOSS_5G_BAND2;
board_params->pcb_loss_5g_band3 = CONFIG_NRF70_PCB_LOSS_5G_BAND3;
#endif /* CONFIG_NRF70_2_4G_ONLY */
}
enum nrf_wifi_status nrf_wifi_fmac_dev_add_zep(struct nrf_wifi_drv_priv_zep *drv_priv_zep)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
void *rpu_ctx = NULL;
enum op_band op_band = CONFIG_NRF_WIFI_OP_BAND;
#ifdef CONFIG_NRF_WIFI_LOW_POWER
int sleep_type = -1;
#ifndef CONFIG_NRF70_RADIO_TEST
sleep_type = HW_SLEEP_ENABLE;
#else
sleep_type = SLEEP_DISABLE;
#endif /* CONFIG_NRF70_RADIO_TEST */
#endif /* CONFIG_NRF_WIFI_LOW_POWER */
struct nrf_wifi_tx_pwr_ctrl_params tx_pwr_ctrl_params;
struct nrf_wifi_tx_pwr_ceil_params tx_pwr_ceil_params;
struct nrf_wifi_board_params board_params;
unsigned int fw_ver = 0;
rpu_ctx_zep = &drv_priv_zep->rpu_ctx_zep;
rpu_ctx_zep->drv_priv_zep = drv_priv_zep;
rpu_ctx = nrf_wifi_fmac_dev_add(drv_priv_zep->fmac_priv, rpu_ctx_zep);
if (!rpu_ctx) {
LOG_ERR("%s: nrf_wifi_fmac_dev_add failed", __func__);
rpu_ctx_zep = NULL;
goto err;
}
rpu_ctx_zep->rpu_ctx = rpu_ctx;
status = nrf_wifi_fw_load(rpu_ctx);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: nrf_wifi_fw_load failed", __func__);
goto err;
}
status = nrf_wifi_fmac_ver_get(rpu_ctx,
&fw_ver);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: FW version read failed", __func__);
goto err;
}
LOG_DBG("Firmware (v%d.%d.%d.%d) booted successfully",
NRF_WIFI_UMAC_VER(fw_ver),
NRF_WIFI_UMAC_VER_MAJ(fw_ver),
NRF_WIFI_UMAC_VER_MIN(fw_ver),
NRF_WIFI_UMAC_VER_EXTRA(fw_ver));
configure_tx_pwr_settings(&tx_pwr_ctrl_params,
&tx_pwr_ceil_params);
configure_board_dep_params(&board_params);
#ifdef CONFIG_NRF70_RADIO_TEST
status = nrf_wifi_fmac_dev_init_rt(rpu_ctx_zep->rpu_ctx,
#ifdef CONFIG_NRF_WIFI_LOW_POWER
sleep_type,
#endif /* CONFIG_NRF_WIFI_LOW_POWER */
NRF_WIFI_DEF_PHY_CALIB,
op_band,
IS_ENABLED(CONFIG_NRF_WIFI_BEAMFORMING),
&tx_pwr_ctrl_params,
&tx_pwr_ceil_params,
&board_params);
#else
status = nrf_wifi_fmac_dev_init(rpu_ctx_zep->rpu_ctx,
#ifdef CONFIG_NRF_WIFI_LOW_POWER
sleep_type,
#endif /* CONFIG_NRF_WIFI_LOW_POWER */
NRF_WIFI_DEF_PHY_CALIB,
op_band,
IS_ENABLED(CONFIG_NRF_WIFI_BEAMFORMING),
&tx_pwr_ctrl_params,
&tx_pwr_ceil_params,
&board_params);
#endif /* CONFIG_NRF70_RADIO_TEST */
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: nrf_wifi_fmac_dev_init failed", __func__);
goto err;
}
k_mutex_init(&rpu_ctx_zep->rpu_lock);
return status;
err:
if (rpu_ctx) {
#ifdef CONFIG_NRF70_RADIO_TEST
nrf_wifi_fmac_dev_rem_rt(rpu_ctx);
#else
nrf_wifi_fmac_dev_rem(rpu_ctx);
#endif /* CONFIG_NRF70_RADIO_TEST */
rpu_ctx_zep->rpu_ctx = NULL;
}
return status;
}
enum nrf_wifi_status nrf_wifi_fmac_dev_rem_zep(struct nrf_wifi_drv_priv_zep *drv_priv_zep)
{
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
rpu_ctx_zep = &drv_priv_zep->rpu_ctx_zep;
#ifdef CONFIG_NRF70_RADIO_TEST
nrf_wifi_fmac_dev_deinit_rt(rpu_ctx_zep->rpu_ctx);
nrf_wifi_fmac_dev_rem_rt(rpu_ctx_zep->rpu_ctx);
#else
nrf_wifi_fmac_dev_deinit(rpu_ctx_zep->rpu_ctx);
nrf_wifi_fmac_dev_rem(rpu_ctx_zep->rpu_ctx);
#endif /* CONFIG_NRF70_RADIO_TEST */
k_free(rpu_ctx_zep->extended_capa);
rpu_ctx_zep->extended_capa = NULL;
k_free(rpu_ctx_zep->extended_capa_mask);
rpu_ctx_zep->extended_capa_mask = NULL;
rpu_ctx_zep->rpu_ctx = NULL;
LOG_DBG("%s: FMAC device removed", __func__);
return NRF_WIFI_STATUS_SUCCESS;
}
static int nrf_wifi_drv_main_zep(const struct device *dev)
{
#ifndef CONFIG_NRF70_RADIO_TEST
struct nrf_wifi_fmac_callbk_fns callbk_fns = { 0 };
struct nrf_wifi_data_config_params data_config = { 0 };
struct rx_buf_pool_params rx_buf_pools[MAX_NUM_OF_RX_QUEUES];
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = dev->data;
vif_ctx_zep->rpu_ctx_zep = &rpu_drv_priv_zep.rpu_ctx_zep;
#ifdef CONFIG_NRF70_DATA_TX
data_config.aggregation = aggregation;
data_config.wmm = wmm;
data_config.max_num_tx_agg_sessions = max_num_tx_agg_sessions;
data_config.max_num_rx_agg_sessions = max_num_rx_agg_sessions;
data_config.max_tx_aggregation = max_tx_aggregation;
data_config.reorder_buf_size = reorder_buf_size;
data_config.max_rxampdu_size = max_rxampdu_size;
data_config.rate_protection_type = rate_protection_type;
callbk_fns.if_carr_state_chg_callbk_fn = nrf_wifi_if_carr_state_chg;
callbk_fns.rx_frm_callbk_fn = nrf_wifi_if_rx_frm;
#if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
callbk_fns.rx_sniffer_frm_callbk_fn = nrf_wifi_if_sniffer_rx_frm;
#endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
#endif
rx_buf_pools[0].num_bufs = rx1_num_bufs;
rx_buf_pools[1].num_bufs = rx2_num_bufs;
rx_buf_pools[2].num_bufs = rx3_num_bufs;
rx_buf_pools[0].buf_sz = rx1_buf_sz;
rx_buf_pools[1].buf_sz = rx2_buf_sz;
rx_buf_pools[2].buf_sz = rx3_buf_sz;
#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
callbk_fns.rpu_recovery_callbk_fn = nrf_wifi_rpu_recovery_cb;
#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
callbk_fns.scan_start_callbk_fn = nrf_wifi_event_proc_scan_start_zep;
callbk_fns.scan_done_callbk_fn = nrf_wifi_event_proc_scan_done_zep;
callbk_fns.reg_change_callbk_fn = reg_change_callbk_fn;
#ifdef CONFIG_NET_L2_WIFI_MGMT
callbk_fns.disp_scan_res_callbk_fn = nrf_wifi_event_proc_disp_scan_res_zep;
#endif /* CONFIG_NET_L2_WIFI_MGMT */
#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS
callbk_fns.rx_bcn_prb_resp_callbk_fn = nrf_wifi_rx_bcn_prb_resp_frm;
#endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */
#if defined(CONFIG_NRF70_SYSTEM_MODE) || defined(CONFIG_NRF70_SYSTEM_WITH_RAW_MODES)
callbk_fns.set_if_callbk_fn = nrf_wifi_set_iface_event_handler;
#endif /* CONFIG_NRF70_SYSTEM_MODE */
#ifdef CONFIG_NRF70_STA_MODE
callbk_fns.twt_config_callbk_fn = nrf_wifi_event_proc_twt_setup_zep;
callbk_fns.twt_teardown_callbk_fn = nrf_wifi_event_proc_twt_teardown_zep;
callbk_fns.twt_sleep_callbk_fn = nrf_wifi_event_proc_twt_sleep_zep;
callbk_fns.event_get_reg = nrf_wifi_event_get_reg_zep;
callbk_fns.event_get_ps_info = nrf_wifi_event_proc_get_power_save_info;
callbk_fns.cookie_rsp_callbk_fn = nrf_wifi_event_proc_cookie_rsp;
callbk_fns.process_rssi_from_rx = nrf_wifi_process_rssi_from_rx;
callbk_fns.scan_res_callbk_fn = nrf_wifi_wpa_supp_event_proc_scan_res;
callbk_fns.auth_resp_callbk_fn = nrf_wifi_wpa_supp_event_proc_auth_resp;
callbk_fns.assoc_resp_callbk_fn = nrf_wifi_wpa_supp_event_proc_assoc_resp;
callbk_fns.deauth_callbk_fn = nrf_wifi_wpa_supp_event_proc_deauth;
callbk_fns.disassoc_callbk_fn = nrf_wifi_wpa_supp_event_proc_disassoc;
callbk_fns.get_station_callbk_fn = nrf_wifi_wpa_supp_event_proc_get_sta;
callbk_fns.get_interface_callbk_fn = nrf_wifi_wpa_supp_event_proc_get_if;
callbk_fns.mgmt_tx_status = nrf_wifi_wpa_supp_event_mgmt_tx_status;
callbk_fns.unprot_mlme_mgmt_rx_callbk_fn = nrf_wifi_wpa_supp_event_proc_unprot_mgmt;
callbk_fns.event_get_wiphy = nrf_wifi_wpa_supp_event_get_wiphy;
callbk_fns.mgmt_rx_callbk_fn = nrf_wifi_wpa_supp_event_mgmt_rx_callbk_fn;
callbk_fns.get_conn_info_callbk_fn = nrf_wifi_supp_event_proc_get_conn_info;
#endif /* CONFIG_NRF70_STA_MODE */
rpu_drv_priv_zep.fmac_priv = nrf_wifi_fmac_init(&data_config,
rx_buf_pools,
&callbk_fns);
#else /* !CONFIG_NRF70_RADIO_TEST */
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
rpu_drv_priv_zep.fmac_priv = nrf_wifi_fmac_init_rt();
#endif /* CONFIG_NRF70_RADIO_TEST */
if (rpu_drv_priv_zep.fmac_priv == NULL) {
LOG_ERR("%s: nrf_wifi_fmac_init failed",
__func__);
goto err;
}
#ifdef CONFIG_NRF70_DATA_TX
struct nrf_wifi_fmac_priv_def *def_priv = NULL;
def_priv = wifi_fmac_priv(rpu_drv_priv_zep.fmac_priv);
def_priv->max_ampdu_len_per_token =
(RPU_PKTRAM_SIZE - (CONFIG_NRF70_RX_NUM_BUFS * CONFIG_NRF70_RX_MAX_DATA_SIZE)) /
CONFIG_NRF70_MAX_TX_TOKENS;
/* Align to 4-byte */
def_priv->max_ampdu_len_per_token &= ~0x3;
/* Alignment overhead for size based coalesce */
def_priv->avail_ampdu_len_per_token =
def_priv->max_ampdu_len_per_token -
(MAX_PKT_RAM_TX_ALIGN_OVERHEAD * max_tx_aggregation);
#endif /* CONFIG_NRF70_DATA_TX */
#ifdef CONFIG_NRF70_RADIO_TEST
status = nrf_wifi_fmac_dev_add_zep(&rpu_drv_priv_zep);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: nrf_wifi_fmac_dev_add_zep failed", __func__);
goto fmac_deinit;
}
#else
k_work_init_delayable(&vif_ctx_zep->scan_timeout_work,
nrf_wifi_scan_timeout_work);
#endif /* CONFIG_NRF70_RADIO_TEST */
return 0;
#ifdef CONFIG_NRF70_RADIO_TEST
fmac_deinit:
nrf_wifi_fmac_deinit_rt(rpu_drv_priv_zep.fmac_priv);
#endif /* CONFIG_NRF70_RADIO_TEST */
err:
return -1;
}
#ifndef CONFIG_NRF70_RADIO_TEST
#ifdef CONFIG_NET_L2_WIFI_MGMT
static struct wifi_mgmt_ops nrf_wifi_mgmt_ops = {
.scan = nrf_wifi_disp_scan_zep,
#ifdef CONFIG_NET_STATISTICS_WIFI
.get_stats = nrf_wifi_stats_get,
#endif /* CONFIG_NET_STATISTICS_WIFI */
#ifdef CONFIG_NRF70_STA_MODE
.set_power_save = nrf_wifi_set_power_save,
.set_twt = nrf_wifi_set_twt,
.reg_domain = nrf_wifi_reg_domain,
.get_power_save_config = nrf_wifi_get_power_save_config,
.set_rts_threshold = nrf_wifi_set_rts_threshold,
#endif /* CONFIG_NRF70_STA_MODE */
#ifdef CONFIG_NRF70_SYSTEM_WITH_RAW_MODES
.mode = nrf_wifi_mode,
#endif
#if defined(CONFIG_NRF70_RAW_DATA_TX) || defined(CONFIG_NRF70_RAW_DATA_RX)
.channel = nrf_wifi_channel,
#endif /* CONFIG_NRF70_RAW_DATA_TX || CONFIG_NRF70_RAW_DATA_RX */
#if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
.filter = nrf_wifi_filter,
#endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
};
#endif /* CONFIG_NET_L2_WIFI_MGMT */
#ifdef CONFIG_NRF70_STA_MODE
static struct zep_wpa_supp_dev_ops wpa_supp_ops = {
.init = nrf_wifi_wpa_supp_dev_init,
.deinit = nrf_wifi_wpa_supp_dev_deinit,
.scan2 = nrf_wifi_wpa_supp_scan2,
.scan_abort = nrf_wifi_wpa_supp_scan_abort,
.get_scan_results2 = nrf_wifi_wpa_supp_scan_results_get,
.deauthenticate = nrf_wifi_wpa_supp_deauthenticate,
.authenticate = nrf_wifi_wpa_supp_authenticate,
.associate = nrf_wifi_wpa_supp_associate,
.set_supp_port = nrf_wifi_wpa_set_supp_port,
.set_key = nrf_wifi_wpa_supp_set_key,
.signal_poll = nrf_wifi_wpa_supp_signal_poll,
.send_mlme = nrf_wifi_nl80211_send_mlme,
.get_wiphy = nrf_wifi_supp_get_wiphy,
.register_frame = nrf_wifi_supp_register_frame,
.get_capa = nrf_wifi_supp_get_capa,
.get_conn_info = nrf_wifi_supp_get_conn_info,
#ifdef CONFIG_NRF70_AP_MODE
.init_ap = nrf_wifi_wpa_supp_init_ap,
.start_ap = nrf_wifi_wpa_supp_start_ap,
.change_beacon = nrf_wifi_wpa_supp_change_beacon,
.stop_ap = nrf_wifi_wpa_supp_stop_ap,
.deinit_ap = nrf_wifi_wpa_supp_deinit_ap,
.sta_add = nrf_wifi_wpa_supp_sta_add,
.sta_remove = nrf_wifi_wpa_supp_sta_remove,
.register_mgmt_frame = nrf_wifi_supp_register_mgmt_frame,
.sta_set_flags = nrf_wifi_wpa_supp_sta_set_flags,
.get_inact_sec = nrf_wifi_wpa_supp_sta_get_inact_sec,
#endif /* CONFIG_NRF70_AP_MODE */
};
#endif /* CONFIG_NRF70_STA_MODE */
#endif /* !CONFIG_NRF70_RADIO_TEST */
#ifdef CONFIG_NET_L2_ETHERNET
static const struct net_wifi_mgmt_offload wifi_offload_ops = {
.wifi_iface.iface_api.init = nrf_wifi_if_init_zep,
.wifi_iface.start = nrf_wifi_if_start_zep,
.wifi_iface.stop = nrf_wifi_if_stop_zep,
.wifi_iface.set_config = nrf_wifi_if_set_config_zep,
.wifi_iface.get_config = nrf_wifi_if_get_config_zep,
.wifi_iface.get_capabilities = nrf_wifi_if_caps_get,
.wifi_iface.send = nrf_wifi_if_send,
#ifdef CONFIG_NET_STATISTICS_ETHERNET
.wifi_iface.get_stats = nrf_wifi_eth_stats_get,
#endif /* CONFIG_NET_STATISTICS_ETHERNET */
#ifdef CONFIG_NET_L2_WIFI_MGMT
.wifi_mgmt_api = &nrf_wifi_mgmt_ops,
#endif /* CONFIG_NET_L2_WIFI_MGMT */
#ifdef CONFIG_NRF70_STA_MODE
.wifi_drv_ops = &wpa_supp_ops,
#endif /* CONFIG_NRF70_STA_MODE */
};
#endif /* CONFIG_NET_L2_ETHERNET */
#ifdef CONFIG_NET_L2_ETHERNET
ETH_NET_DEVICE_DT_INST_DEFINE(0,
nrf_wifi_drv_main_zep, /* init_fn */
NULL, /* pm_action_cb */
&rpu_drv_priv_zep.rpu_ctx_zep.vif_ctx_zep[0], /* data */
#ifdef CONFIG_NRF70_STA_MODE
&wpa_supp_ops, /* cfg */
#else /* CONFIG_NRF70_STA_MODE */
NULL, /* cfg */
#endif /* !CONFIG_NRF70_STA_MODE */
CONFIG_WIFI_INIT_PRIORITY, /* prio */
&wifi_offload_ops, /* api */
CONFIG_NRF_WIFI_IFACE_MTU); /*mtu */
#else
DEVICE_DT_INST_DEFINE(0,
nrf_wifi_drv_main_zep, /* init_fn */
NULL, /* pm_action_cb */
#ifndef CONFIG_NRF70_RADIO_TEST
&rpu_drv_priv_zep, /* data */
#else /* !CONFIG_NRF70_RADIO_TEST */
NULL,
#endif /* CONFIG_NRF70_RADIO_TEST */
NULL, /* cfg */
POST_KERNEL,
CONFIG_WIFI_INIT_PRIORITY, /* prio */
NULL); /* api */
#endif /* CONFIG_NRF70_STA_MODE */
#ifdef CONFIG_NET_CONNECTION_MANAGER_CONNECTIVITY_WIFI_MGMT
CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0)), L2_CONN_WLAN0);
#endif /* CONFIG_NET_CONNECTION_MANAGER_CONNECTIVITY_WIFI_MGMT */

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing FW load functions for Zephyr.
*/
#include <stdlib.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
#include <fmac_main.h>
#ifdef CONFIG_NRF_WIFI_PATCHES_BUILTIN
/* INCBIN macro Taken from https://gist.github.com/mmozeiko/ed9655cf50341553d282 */
#define STR2(x) #x
#define STR(x) STR2(x)
#ifdef __APPLE__
#define USTR(x) "_" STR(x)
#else
#define USTR(x) STR(x)
#endif
#ifdef _WIN32
#define INCBIN_SECTION ".rdata, \"dr\""
#elif defined __APPLE__
#define INCBIN_SECTION "__TEXT,__const"
#else
#define INCBIN_SECTION ".rodata.*"
#endif
/* this aligns start address to 16 and terminates byte array with explicit 0
* which is not really needed, feel free to change it to whatever you want/need
*/
#define INCBIN(prefix, name, file) \
__asm__(".section " INCBIN_SECTION "\n" \
".global " USTR(prefix) "_" STR(name) "_start\n" \
".balign 16\n" \
USTR(prefix) "_" STR(name) "_start:\n" \
".incbin \"" file "\"\n" \
\
".global " STR(prefix) "_" STR(name) "_end\n" \
".balign 1\n" \
USTR(prefix) "_" STR(name) "_end:\n" \
".byte 0\n" \
); \
extern __aligned(16) const char prefix ## _ ## name ## _start[]; \
extern const char prefix ## _ ## name ## _end[];
INCBIN(_bin, nrf70_fw, STR(CONFIG_NRF_WIFI_FW_BIN));
#endif /* CONFIG_NRF_WIFI_PATCHES_BUILTIN */
enum nrf_wifi_status nrf_wifi_fw_load(void *rpu_ctx)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct nrf_wifi_fmac_fw_info fw_info = { 0 };
uint8_t *fw_start;
uint8_t *fw_end;
fw_start = (uint8_t *)_bin_nrf70_fw_start;
fw_end = (uint8_t *)_bin_nrf70_fw_end;
status = nrf_wifi_fmac_fw_parse(rpu_ctx, fw_start, fw_end - fw_start,
&fw_info);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: nrf_wifi_fmac_fw_parse failed", __func__);
return status;
}
/* 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__);
}
return status;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing address/offets and functions for writing
* the FICR fields of the OTP memory on nRF7002 device
*/
#ifndef __OTP_PROG_H_
#define __OTP_PROG_H_
#include <stdio.h>
#include <stdlib.h>
int write_otp_memory(unsigned int otp_addr, unsigned int *write_val);
int read_otp_memory(unsigned int otp_addr, unsigned int *read_val, int len);
unsigned int check_protection(unsigned int *buff, unsigned int off1, unsigned int off2,
unsigned int off3, unsigned int off4);
#endif /* __OTP_PROG_H_ */

View file

@ -0,0 +1,116 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing QSPI device interface specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __QSPI_IF_H__
#define __QSPI_IF_H__
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#ifdef CONFIG_NRF70_ON_QSPI
#include <nrfx_qspi.h>
#endif
#define RPU_WAKEUP_NOW BIT(0) /* WAKEUP RPU - RW */
#define RPU_AWAKE_BIT BIT(1) /* RPU AWAKE FROM SLEEP - RO */
#define RPU_READY_BIT BIT(2) /* RPU IS READY - RO*/
struct qspi_config {
#ifdef CONFIG_NRF70_ON_QSPI
nrf_qspi_addrmode_t addrmode;
nrf_qspi_readoc_t readoc;
nrf_qspi_writeoc_t writeoc;
nrf_qspi_frequency_t sckfreq;
#endif
unsigned char RDC4IO;
bool easydma;
bool single_op;
bool quad_spi;
bool encryption;
bool CMD_CNONCE;
bool enc_enabled;
struct k_sem lock;
unsigned int addrmask;
unsigned char qspi_slave_latency;
#if defined(CONFIG_NRF70_ON_QSPI) && (NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC)
nrf_qspi_encryption_t p_cfg;
#endif /*CONFIG_NRF70_ON_QSPI && (NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC)*/
int test_hlread;
char *test_name;
int test_start;
int test_end;
int test_iterations;
int test_timediff_read;
int test_timediff_write;
int test_status;
int test_iteration;
};
struct qspi_dev {
int (*deinit)(void);
void *config;
int (*init)(struct qspi_config *config);
int (*write)(unsigned int addr, const void *data, int len);
int (*read)(unsigned int addr, void *data, int len);
int (*hl_read)(unsigned int addr, void *data, int len);
void (*hard_reset)(void);
};
int qspi_cmd_wakeup_rpu(const struct device *dev, uint8_t data);
int qspi_init(struct qspi_config *config);
int qspi_write(unsigned int addr, const void *data, int len);
int qspi_read(unsigned int addr, void *data, int len);
int qspi_hl_read(unsigned int addr, void *data, int len);
int qspi_deinit(void);
void gpio_free_irq(int pin, struct gpio_callback *button_cb_data);
int gpio_request_irq(int pin, struct gpio_callback *button_cb_data, void (*irq_handler)());
struct qspi_config *qspi_defconfig(void);
struct qspi_dev *qspi_dev(void);
struct qspi_config *qspi_get_config(void);
int qspi_cmd_sleep_rpu(const struct device *dev);
void hard_reset(void);
void get_sleep_stats(uint32_t addr, uint32_t *buff, uint32_t wrd_len);
extern struct device qspi_perip;
int qspi_validate_rpu_wake_writecmd(const struct device *dev);
int qspi_cmd_wakeup_rpu(const struct device *dev, uint8_t data);
int qspi_wait_while_rpu_awake(const struct device *dev);
int qspi_RDSR1(const struct device *dev, uint8_t *rdsr1);
int qspi_RDSR2(const struct device *dev, uint8_t *rdsr2);
int qspi_WRSR2(const struct device *dev, const uint8_t wrsr2);
#ifdef CONFIG_NRF_WIFI_LOW_POWER
int func_rpu_sleep(void);
int func_rpu_wake(void);
int func_rpu_sleep_status(void);
#endif /* CONFIG_NRF_WIFI_LOW_POWER */
#define QSPI_KEY_LEN_BYTES 16
/*! \brief Enable encryption
*
* \param key Pointer to the 128-bit key
* \return 0 on success, negative errno code on failure.
*/
int qspi_enable_encryption(uint8_t *key);
#endif /* __QSPI_IF_H__ */

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing common functions for RPU hardware interaction
* using QSPI and SPI that can be invoked by shell or the driver.
*/
#ifndef __RPU_HW_IF_H_
#define __RPU_HW_IF_H_
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/drivers/gpio.h>
enum {
SYSBUS = 0,
EXT_SYS_BUS,
PBUS,
PKTRAM,
GRAM,
LMAC_ROM,
LMAC_RET_RAM,
LMAC_SRC_RAM,
UMAC_ROM,
UMAC_RET_RAM,
UMAC_SRC_RAM,
NUM_MEM_BLOCKS
};
extern char blk_name[][15];
extern uint32_t rpu_7002_memmap[][3];
int rpu_read(unsigned int addr, void *data, int len);
int rpu_write(unsigned int addr, const void *data, int len);
int rpu_sleep(void);
int rpu_wakeup(void);
int rpu_sleep_status(void);
void rpu_get_sleep_stats(uint32_t addr, uint32_t *buff, uint32_t wrd_len);
int rpu_irq_config(struct gpio_callback *irq_callback_data, void (*irq_handler)());
int rpu_irq_remove(struct gpio_callback *irq_callback_data);
int rpu_wrsr2(uint8_t data);
int rpu_rdsr2(void);
int rpu_rdsr1(void);
int rpu_clks_on(void);
int rpu_init(void);
int rpu_enable(void);
int rpu_disable(void);
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
int sr_ant_switch(unsigned int ant_switch);
int sr_gpio_remove(void);
int sr_gpio_config(void);
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
#endif /* __RPU_HW_IF_H_ */

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing SPI device interface specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
/* SPIM driver config */
int spim_init(struct qspi_config *config);
int spim_deinit(void);
int spim_write(unsigned int addr, const void *data, int len);
int spim_read(unsigned int addr, void *data, int len);
int spim_hl_read(unsigned int addr, void *data, int len);
int spim_cmd_rpu_wakeup_fn(uint32_t data);
int spim_wait_while_rpu_awake(void);
int spi_validate_rpu_wake_writecmd(void);
int spim_cmd_sleep_rpu_fn(void);
int spim_RDSR1(const struct device *dev, uint8_t *rdsr1);
int spim_RDSR2(const struct device *dev, uint8_t *rdsr2);
int spim_WRSR2(const struct device *dev, const uint8_t wrsr2);

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing SPI device specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __SPI_NOR_H__
#define __SPI_NOR_H__
#include <zephyr/sys/util.h>
#define SPI_NOR_MAX_ID_LEN 3
/* Status register bits */
#define SPI_NOR_WIP_BIT BIT(0) /* Write in progress */
#define SPI_NOR_WEL_BIT BIT(1) /* Write enable latch */
/* Flash opcodes */
#define SPI_NOR_CMD_WRSR 0x01 /* Write status register */
#define SPI_NOR_CMD_RDSR 0x05 /* Read status register */
#define SPI_NOR_CMD_READ 0x03 /* Read data */
#define SPI_NOR_CMD_WREN 0x06 /* Write enable */
#define SPI_NOR_CMD_WRDI 0x04 /* Write disable */
#define SPI_NOR_CMD_PP 0x02 /* Page program */
#define SPI_NOR_CMD_SE 0x20 /* Sector erase */
#define SPI_NOR_CMD_BE_32K 0x52 /* Block erase 32KB */
#define SPI_NOR_CMD_BE 0xD8 /* Block erase */
#define SPI_NOR_CMD_CE 0xC7 /* Chip erase */
#define SPI_NOR_CMD_RDID 0x9F /* Read JEDEC ID */
#define SPI_NOR_CMD_ULBPR 0x98 /* Global Block Protection Unlock */
#define SPI_NOR_CMD_4BA 0xB7 /* Enter 4-Byte Address Mode */
#define SPI_NOR_CMD_DPD 0xB9 /* Deep Power Down */
#define SPI_NOR_CMD_RDPD 0xAB /* Release from Deep Power Down */
/* Page, sector, and block size are standard, not configurable. */
#define SPI_NOR_PAGE_SIZE 0x0100U
#define SPI_NOR_SECTOR_SIZE 0x1000U
#define SPI_NOR_BLOCK_SIZE 0x10000U
/* Test whether offset is aligned to a given number of bits. */
#define SPI_NOR_IS_ALIGNED(_ofs, _bits) (((_ofs)&BIT_MASK(_bits)) == 0)
#define SPI_NOR_IS_SECTOR_ALIGNED(_ofs) SPI_NOR_IS_ALIGNED(_ofs, 12)
#endif /*__SPI_NOR_H__*/

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing QSPI device specific definitions for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/gpio.h>
#include <stdio.h>
#include <string.h>
#include "qspi_if.h"
#include "spi_if.h"
static struct qspi_config config;
#if defined(CONFIG_NRF70_ON_QSPI)
static struct qspi_dev qspi = {
.init = qspi_init,
.deinit = qspi_deinit,
.read = qspi_read,
.write = qspi_write,
.hl_read = qspi_hl_read
};
#else
static struct qspi_dev spim = {
.init = spim_init,
.deinit = spim_deinit,
.read = spim_read,
.write = spim_write,
.hl_read = spim_hl_read
};
#endif
struct qspi_config *qspi_defconfig(void)
{
memset(&config, 0, sizeof(struct qspi_config));
#if defined(CONFIG_NRF70_ON_QSPI)
config.addrmode = NRF_QSPI_ADDRMODE_24BIT;
config.RDC4IO = 0xA0;
config.easydma = true;
config.quad_spi = true;
#endif
config.addrmask = 0x800000; /* set bit23 (incr. addr mode) */
config.test_name = "QSPI TEST";
config.test_hlread = false;
config.test_iteration = 0;
config.qspi_slave_latency = 0;
config.encryption = config.CMD_CNONCE = false;
#if defined(CONFIG_NRF70_ON_QSPI) && (NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC)
/*For #Bit 6 Enable below: i.e ALL Ones for QSPI Key*/
memset(&config.p_cfg.key, 0xff, sizeof(config.p_cfg.key));
config.p_cfg.nonce[0] = 0x16181648;
config.p_cfg.nonce[1] = 0x0;
config.p_cfg.nonce[2] = 0x1;
#endif /*CONFIG_NRF70_ON_QSPI && (NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC)*/
return &config;
}
struct qspi_config *qspi_get_config(void)
{
return &config;
}
struct qspi_dev *qspi_dev(void)
{
#if CONFIG_NRF70_ON_QSPI
return &qspi;
#else
return &spim;
#endif
}

View file

@ -0,0 +1,379 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/* @file
* @brief NRF Wi-Fi radio FICR programming functions
*/
#include <zephyr/logging/log.h>
#include <zephyr/kernel.h>
#include "rpu_if.h"
#include "rpu_hw_if.h"
#include "ficr_prog.h"
LOG_MODULE_DECLARE(otp_prog, CONFIG_WIFI_NRF70_BUS_LOG_LEVEL);
static void write_word(unsigned int addr, unsigned int data)
{
rpu_write(addr, &data, 4);
}
static void read_word(unsigned int addr, unsigned int *data)
{
rpu_read(addr, data, 4);
}
unsigned int check_protection(unsigned int *buff, unsigned int off1, unsigned int off2,
unsigned int off3, unsigned int off4)
{
if ((buff[off1] == OTP_PROGRAMMED) &&
(buff[off2] == OTP_PROGRAMMED) &&
(buff[off3] == OTP_PROGRAMMED) &&
(buff[off4] == OTP_PROGRAMMED))
return OTP_PROGRAMMED;
else if ((buff[off1] == OTP_FRESH_FROM_FAB) &&
(buff[off2] == OTP_FRESH_FROM_FAB) &&
(buff[off3] == OTP_FRESH_FROM_FAB) &&
(buff[off4] == OTP_FRESH_FROM_FAB))
return OTP_FRESH_FROM_FAB;
else if ((buff[off1] == OTP_ENABLE_PATTERN) &&
(buff[off2] == OTP_ENABLE_PATTERN) &&
(buff[off3] == OTP_ENABLE_PATTERN) &&
(buff[off4] == OTP_ENABLE_PATTERN))
return OTP_ENABLE_PATTERN;
else
return OTP_INVALID;
}
static void set_otp_timing_reg_40mhz(void)
{
write_word(OTP_TIMING_REG1_ADDR, OTP_TIMING_REG1_VAL);
write_word(OTP_TIMING_REG2_ADDR, OTP_TIMING_REG2_VAL);
}
static int poll_otp_ready(void)
{
int otp_mem_status = 0;
int poll = 0;
while (poll != 100) {
read_word(OTP_POLL_ADDR, &otp_mem_status);
if ((otp_mem_status & OTP_READY) == OTP_READY) {
return 0;
}
poll++;
}
LOG_ERR("OTP is not ready");
return -ENOEXEC;
}
static int req_otp_standby_mode(void)
{
write_word(OTP_RWSBMODE_ADDR, 0x0);
return poll_otp_ready();
}
static int otp_wr_voltage_2V5(void)
{
int err;
err = req_otp_standby_mode();
if (err) {
LOG_ERR("Failed Setting OTP voltage IOVDD to 2.5V");
return -ENOEXEC;
}
write_word(OTP_VOLTCTRL_ADDR, OTP_VOLTCTRL_2V5);
return 0;
}
static int poll_otp_read_valid(void)
{
int otp_mem_status = 0;
int poll = 0;
while (poll < 100) {
read_word(OTP_POLL_ADDR, &otp_mem_status);
if ((otp_mem_status & OTP_READ_VALID) == OTP_READ_VALID) {
return 0;
}
poll++;
}
LOG_ERR("%s: OTP read failed", __func__);
return -ENOEXEC;
}
static int poll_otp_wrdone(void)
{
int otp_mem_status = 0;
int poll = 0;
while (poll < 100) {
read_word(OTP_POLL_ADDR, &otp_mem_status);
if ((otp_mem_status & OTP_WR_DONE) == OTP_WR_DONE) {
return 0;
}
poll++;
}
LOG_ERR("%s: OTP write done failed", __func__);
return -ENOEXEC;
}
static int req_otp_read_mode(void)
{
write_word(OTP_RWSBMODE_ADDR, OTP_READ_MODE);
return poll_otp_ready();
}
static int req_otp_byte_write_mode(void)
{
write_word(OTP_RWSBMODE_ADDR, OTP_BYTE_WRITE_MODE);
return poll_otp_ready();
}
static unsigned int read_otp_location(unsigned int offset, unsigned int *read_val)
{
int err;
write_word(OTP_RDENABLE_ADDR, offset);
err = poll_otp_read_valid();
if (err) {
LOG_ERR("OTP read failed");
return err;
}
read_word(OTP_READREG_ADDR, read_val);
return 0;
}
static int write_otp_location(unsigned int otp_location_offset, unsigned int otp_data)
{
write_word(OTP_WRENABLE_ADDR, otp_location_offset);
write_word(OTP_WRITEREG_ADDR, otp_data);
return poll_otp_wrdone();
}
static int otp_rd_voltage_1V8(void)
{
int err;
err = req_otp_standby_mode();
if (err) {
LOG_ERR("error in %s", __func__);
return err;
}
write_word(OTP_VOLTCTRL_ADDR, OTP_VOLTCTRL_1V8);
return 0;
}
static int update_mac_addr(unsigned int index, unsigned int *write_val)
{
int ret = 0;
for (int i = 0; i < 2; i++) {
ret = write_otp_location(MAC0_ADDR + 2 * index + i, write_val[i]);
if (ret == -ENOEXEC) {
LOG_ERR("FICR: Failed to update MAC ADDR%d", index);
break;
}
LOG_INF("mac addr %d : Reg%d (0x%x) = 0x%04x",
index, (i+1), (MAC0_ADDR + i) << 2, write_val[i]);
}
return ret;
}
int write_otp_memory(unsigned int otp_addr, unsigned int *write_val)
{
int err = 0;
int mask_val;
int ret = 0;
int retrim_loc = 0;
err = poll_otp_ready();
if (err) {
LOG_ERR("err in otp ready poll");
return err;
}
set_otp_timing_reg_40mhz();
err = otp_wr_voltage_2V5();
if (err) {
LOG_ERR("error in write_voltage 2V5");
goto _exit_otp_write;
}
err = req_otp_byte_write_mode();
if (err) {
LOG_ERR("error in OTP byte write mode");
goto _exit_otp_write;
}
switch (otp_addr) {
case REGION_PROTECT:
write_otp_location(REGION_PROTECT, write_val[0]);
write_otp_location(REGION_PROTECT+1, write_val[0]);
write_otp_location(REGION_PROTECT+2, write_val[0]);
write_otp_location(REGION_PROTECT+3, write_val[0]);
LOG_INF("Written REGION_PROTECT0 (0x%x) : 0x%04x",
(REGION_PROTECT << 2), write_val[0]);
LOG_INF("Written REGION_PROTECT1 (0x%x) : 0x%04x",
(REGION_PROTECT+1) << 2, write_val[0]);
LOG_INF("Written REGION_PROTECT2 (0x%x) : 0x%04x",
(REGION_PROTECT+2) << 2, write_val[0]);
LOG_INF("Written REGION_PROTECT3 (0x%x) : 0x%04x",
(REGION_PROTECT+3) << 2, write_val[0]);
break;
case QSPI_KEY:
mask_val = QSPI_KEY_FLAG_MASK;
for (int i = 0; i < QSPI_KEY_LENGTH_BYTES / 4; i++) {
ret = write_otp_location(QSPI_KEY + i, write_val[i]);
if (ret == -ENOEXEC) {
LOG_ERR("FICR: Failed to write QSPI key offset-%d", QSPI_KEY + i);
goto _exit_otp_write;
}
LOG_INF("Written QSPI_KEY0 (0x%x) : 0x%04x",
(QSPI_KEY + i) << 2, write_val[i]);
}
write_otp_location(REGION_DEFAULTS, mask_val);
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
break;
case MAC0_ADDR:
mask_val = MAC0_ADDR_FLAG_MASK;
ret = update_mac_addr(0, write_val);
if (ret == -ENOEXEC) {
goto _exit_otp_write;
}
write_otp_location(REGION_DEFAULTS, mask_val);
LOG_INF("Written MAC address 0");
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
break;
case MAC1_ADDR:
mask_val = MAC1_ADDR_FLAG_MASK;
ret = update_mac_addr(1, write_val);
if (ret == -ENOEXEC) {
goto _exit_otp_write;
}
write_otp_location(REGION_DEFAULTS, mask_val);
LOG_INF("Written MAC address 1");
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
break;
case CALIB_XO:
mask_val = CALIB_XO_FLAG_MASK;
ret = write_otp_location(CALIB_XO, write_val[0]);
if (ret == -ENOEXEC) {
LOG_ERR("XO_Update Exception");
goto _exit_otp_write;
} else {
write_otp_location(REGION_DEFAULTS, mask_val);
LOG_INF("Written CALIB_XO (0x%x) to 0x%04x",
CALIB_XO << 2, write_val[0]);
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
}
break;
case PRODRETEST_PROGVERSION:
ret = write_otp_location(PRODRETEST_PROGVERSION, *write_val);
if (ret == -ENOEXEC) {
LOG_ERR("PRODRETEST.PROGVERSION_Update Exception");
goto _exit_otp_write;
} else {
LOG_INF("Written PRODRETEST.PROGVERSION 0x%04x", *write_val);
}
break;
case PRODRETEST_TRIM0:
case PRODRETEST_TRIM1:
case PRODRETEST_TRIM2:
case PRODRETEST_TRIM3:
case PRODRETEST_TRIM4:
case PRODRETEST_TRIM5:
case PRODRETEST_TRIM6:
case PRODRETEST_TRIM7:
case PRODRETEST_TRIM8:
case PRODRETEST_TRIM9:
case PRODRETEST_TRIM10:
case PRODRETEST_TRIM11:
case PRODRETEST_TRIM12:
case PRODRETEST_TRIM13:
case PRODRETEST_TRIM14:
retrim_loc = otp_addr - PRODRETEST_TRIM0;
ret = write_otp_location(otp_addr, *write_val);
if (ret == -ENOEXEC) {
LOG_ERR("PRODRETEST.TRIM_Update Exception");
goto _exit_otp_write;
} else {
LOG_INF("Written PRODRETEST.TRIM%d 0x%04x",
retrim_loc, *write_val);
}
break;
case REGION_DEFAULTS:
write_otp_location(REGION_DEFAULTS, write_val[0]);
LOG_INF("Written REGION_DEFAULTS (0x%x) to 0x%04x",
REGION_DEFAULTS << 2, write_val[0]);
break;
default:
LOG_ERR("unknown field received: %d", otp_addr);
}
return ret;
_exit_otp_write:
err = req_otp_standby_mode();
err |= otp_rd_voltage_1V8();
return err;
}
int read_otp_memory(unsigned int otp_addr, unsigned int *read_val, int len)
{
int err;
err = poll_otp_ready();
if (err) {
LOG_ERR("err in otp ready poll");
return -ENOEXEC;
}
set_otp_timing_reg_40mhz();
err = otp_rd_voltage_1V8();
if (err) {
LOG_ERR("error in read_voltage 1V8");
return -ENOEXEC;
}
err = req_otp_read_mode();
if (err) {
LOG_ERR("error in req_otp_read_mode()");
return -ENOEXEC;
}
for (int i = 0; i < len; i++) {
read_otp_location(otp_addr + i, &read_val[i]);
}
return req_otp_standby_mode();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,489 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing common functions for RPU hardware interaction
* using QSPI and SPI that can be invoked by shell or the driver.
*/
#include <string.h>
#include <sys/time.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/devicetree.h>
#include <zephyr/dt-bindings/gpio/nordic-nrf-gpio.h>
#include <zephyr/logging/log.h>
#include "rpu_hw_if.h"
#include "qspi_if.h"
#include "spi_if.h"
LOG_MODULE_REGISTER(wifi_nrf_bus, CONFIG_WIFI_NRF70_BUS_LOG_LEVEL);
#define NRF7002_NODE DT_NODELABEL(nrf70)
static const struct gpio_dt_spec host_irq_spec =
GPIO_DT_SPEC_GET(NRF7002_NODE, host_irq_gpios);
static const struct gpio_dt_spec iovdd_ctrl_spec =
GPIO_DT_SPEC_GET(NRF7002_NODE, iovdd_ctrl_gpios);
static const struct gpio_dt_spec bucken_spec =
GPIO_DT_SPEC_GET(NRF7002_NODE, bucken_gpios);
char blk_name[][15] = { "SysBus", "ExtSysBus", "PBus", "PKTRAM",
"GRAM", "LMAC_ROM", "LMAC_RET_RAM", "LMAC_SRC_RAM",
"UMAC_ROM", "UMAC_RET_RAM", "UMAC_SRC_RAM" };
uint32_t rpu_7002_memmap[][3] = {
{ 0x000000, 0x008FFF, 1 },
{ 0x009000, 0x03FFFF, 2 },
{ 0x040000, 0x07FFFF, 1 },
{ 0x0C0000, 0x0F0FFF, 0 },
{ 0x080000, 0x092000, 1 },
{ 0x100000, 0x134000, 1 },
{ 0x140000, 0x14C000, 1 },
{ 0x180000, 0x190000, 1 },
{ 0x200000, 0x261800, 1 },
{ 0x280000, 0x2A4000, 1 },
{ 0x300000, 0x338000, 1 }
};
static const struct qspi_dev *qdev;
static struct qspi_config *cfg;
static int validate_addr_blk(uint32_t start_addr,
uint32_t end_addr,
uint32_t block_no,
bool *hl_flag,
int *selected_blk)
{
uint32_t *block_map = rpu_7002_memmap[block_no];
if (((start_addr >= block_map[0]) && (start_addr <= block_map[1])) &&
((end_addr >= block_map[0]) && (end_addr <= block_map[1]))) {
if (block_no == PKTRAM) {
*hl_flag = 0;
}
*selected_blk = block_no;
return 0;
}
return -1;
}
static int rpu_validate_addr(uint32_t start_addr, uint32_t len, bool *hl_flag)
{
int ret = 0, i;
uint32_t end_addr;
int selected_blk;
end_addr = start_addr + len - 1;
*hl_flag = 1;
for (i = 0; i < NUM_MEM_BLOCKS; i++) {
ret = validate_addr_blk(start_addr, end_addr, i, hl_flag, &selected_blk);
if (!ret) {
break;
}
}
if (ret) {
LOG_ERR("Address validation failed - pls check memmory map and re-try");
return -1;
}
if ((selected_blk == LMAC_ROM) || (selected_blk == UMAC_ROM)) {
LOG_ERR("Error: Cannot write to ROM blocks");
return -1;
}
cfg->qspi_slave_latency = (*hl_flag) ? rpu_7002_memmap[selected_blk][2] : 0;
return 0;
}
int rpu_irq_config(struct gpio_callback *irq_callback_data, void (*irq_handler)())
{
int ret;
if (!device_is_ready(host_irq_spec.port)) {
LOG_ERR("Host IRQ GPIO %s is not ready", host_irq_spec.port->name);
return -ENODEV;
}
ret = gpio_pin_configure_dt(&host_irq_spec, GPIO_INPUT);
if (ret) {
LOG_ERR("Failed to configure host_irq pin %d", host_irq_spec.pin);
goto out;
}
ret = gpio_pin_interrupt_configure_dt(&host_irq_spec,
GPIO_INT_EDGE_TO_ACTIVE);
if (ret) {
LOG_ERR("Failed to configure interrupt on host_irq pin %d",
host_irq_spec.pin);
goto out;
}
gpio_init_callback(irq_callback_data,
irq_handler,
BIT(host_irq_spec.pin));
ret = gpio_add_callback(host_irq_spec.port, irq_callback_data);
if (ret) {
LOG_ERR("Failed to add callback on host_irq pin %d",
host_irq_spec.pin);
goto out;
}
LOG_DBG("Finished Interrupt config\n");
out:
return ret;
}
int rpu_irq_remove(struct gpio_callback *irq_callback_data)
{
int ret;
ret = gpio_pin_configure_dt(&host_irq_spec, GPIO_DISCONNECTED);
if (ret) {
LOG_ERR("Failed to remove host_irq pin %d", host_irq_spec.pin);
goto out;
}
ret = gpio_remove_callback(host_irq_spec.port, irq_callback_data);
if (ret) {
LOG_ERR("Failed to remove callback on host_irq pin %d",
host_irq_spec.pin);
goto out;
}
out:
return ret;
}
static int rpu_gpio_config(void)
{
int ret;
if (!device_is_ready(iovdd_ctrl_spec.port)) {
LOG_ERR("IOVDD GPIO %s is not ready", iovdd_ctrl_spec.port->name);
return -ENODEV;
}
if (!device_is_ready(bucken_spec.port)) {
LOG_ERR("BUCKEN GPIO %s is not ready", bucken_spec.port->name);
return -ENODEV;
}
ret = gpio_pin_configure_dt(&bucken_spec, (GPIO_OUTPUT | NRF_GPIO_DRIVE_H0H1));
if (ret) {
LOG_ERR("BUCKEN GPIO configuration failed...");
return ret;
}
ret = gpio_pin_configure_dt(&iovdd_ctrl_spec, GPIO_OUTPUT);
if (ret) {
LOG_ERR("IOVDD GPIO configuration failed...");
gpio_pin_configure_dt(&bucken_spec, GPIO_DISCONNECTED);
return ret;
}
LOG_DBG("GPIO configuration done...\n");
return 0;
}
static int rpu_gpio_remove(void)
{
int ret;
ret = gpio_pin_configure_dt(&bucken_spec, GPIO_DISCONNECTED);
if (ret) {
LOG_ERR("BUCKEN GPIO remove failed...");
return ret;
}
ret = gpio_pin_configure_dt(&iovdd_ctrl_spec, GPIO_DISCONNECTED);
if (ret) {
LOG_ERR("IOVDD GPIO remove failed...");
return ret;
}
LOG_DBG("GPIO remove done...\n");
return ret;
}
static int rpu_pwron(void)
{
int ret;
ret = gpio_pin_set_dt(&bucken_spec, 1);
if (ret) {
LOG_ERR("BUCKEN GPIO set failed...");
return ret;
}
/* Settling time is 50us (H0) or 100us (L0) */
k_msleep(1);
ret = gpio_pin_set_dt(&iovdd_ctrl_spec, 1);
if (ret) {
LOG_ERR("IOVDD GPIO set failed...");
gpio_pin_set_dt(&bucken_spec, 0);
return ret;
}
/* Settling time for iovdd nRF7002 DK/EK - switch (TCK106AG): ~600us */
k_msleep(1);
if (IS_ENABLED(CONFIG_NRF_WIFI_COMBINED_BUCKEN_IOVDD_GPIO)) {
/* When a single GPIO is used, we need a total wait time after bucken assertion
* to be 6ms (1ms + 1ms + 4ms).
*/
k_msleep(4);
}
LOG_DBG("Bucken = %d, IOVDD = %d", gpio_pin_get_dt(&bucken_spec),
gpio_pin_get_dt(&iovdd_ctrl_spec));
return ret;
}
static int rpu_pwroff(void)
{
int ret;
ret = gpio_pin_set_dt(&bucken_spec, 0); /* BUCKEN = 0 */
if (ret) {
LOG_ERR("BUCKEN GPIO set failed...");
return ret;
}
ret = gpio_pin_set_dt(&iovdd_ctrl_spec, 0); /* IOVDD CNTRL = 0 */
if (ret) {
LOG_ERR("IOVDD GPIO set failed...");
return ret;
}
return ret;
}
int rpu_read(unsigned int addr, void *data, int len)
{
bool hl_flag;
if (rpu_validate_addr(addr, len, &hl_flag)) {
return -1;
}
if (hl_flag)
return qdev->hl_read(addr, data, len);
else
return qdev->read(addr, data, len);
}
int rpu_write(unsigned int addr, const void *data, int len)
{
bool hl_flag;
if (rpu_validate_addr(addr, len, &hl_flag)) {
return -1;
}
return qdev->write(addr, data, len);
}
int rpu_sleep(void)
{
#if CONFIG_NRF70_ON_QSPI
return qspi_cmd_sleep_rpu(&qspi_perip);
#else
return spim_cmd_sleep_rpu_fn();
#endif
}
int rpu_wakeup(void)
{
int ret;
ret = rpu_wrsr2(1);
if (ret) {
LOG_ERR("Error: WRSR2 failed");
return ret;
}
ret = rpu_rdsr2();
if (ret < 0) {
LOG_ERR("Error: RDSR2 failed");
return ret;
}
ret = rpu_rdsr1();
if (ret < 0) {
LOG_ERR("Error: RDSR1 failed");
return ret;
}
return 0;
}
int rpu_sleep_status(void)
{
return rpu_rdsr1();
}
void rpu_get_sleep_stats(uint32_t addr, uint32_t *buff, uint32_t wrd_len)
{
int ret;
ret = rpu_wakeup();
if (ret) {
LOG_ERR("Error: RPU wakeup failed");
return;
}
ret = rpu_read(addr, buff, wrd_len * 4);
if (ret) {
LOG_ERR("Error: RPU read failed");
return;
}
ret = rpu_sleep();
if (ret) {
LOG_ERR("Error: RPU sleep failed");
return;
}
}
int rpu_wrsr2(uint8_t data)
{
int ret;
#if CONFIG_NRF70_ON_QSPI
ret = qspi_cmd_wakeup_rpu(&qspi_perip, data);
#else
ret = spim_cmd_rpu_wakeup_fn(data);
#endif
LOG_DBG("Written 0x%x to WRSR2", data);
return ret;
}
int rpu_rdsr2(void)
{
#if CONFIG_NRF70_ON_QSPI
return qspi_validate_rpu_wake_writecmd(&qspi_perip);
#else
return spi_validate_rpu_wake_writecmd();
#endif
}
int rpu_rdsr1(void)
{
#if CONFIG_NRF70_ON_QSPI
return qspi_wait_while_rpu_awake(&qspi_perip);
#else
return spim_wait_while_rpu_awake();
#endif
}
int rpu_clks_on(void)
{
uint32_t rpu_clks = 0x100;
/* Enable RPU Clocks */
qdev->write(0x048C20, &rpu_clks, 4);
LOG_DBG("RPU Clocks ON...");
return 0;
}
int rpu_init(void)
{
int ret;
qdev = qspi_dev();
cfg = qspi_get_config();
ret = rpu_gpio_config();
if (ret) {
goto out;
}
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
ret = sr_gpio_config();
if (ret) {
goto remove_rpu_gpio;
}
#endif
ret = rpu_pwron();
if (ret) {
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
goto remove_sr_gpio;
#else
goto remove_rpu_gpio;
#endif
}
return 0;
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
remove_sr_gpio:
sr_gpio_remove();
#endif
remove_rpu_gpio:
rpu_gpio_remove();
out:
return ret;
}
int rpu_enable(void)
{
int ret;
ret = rpu_wakeup();
if (ret) {
goto rpu_pwroff;
}
ret = rpu_clks_on();
if (ret) {
goto rpu_pwroff;
}
return 0;
rpu_pwroff:
rpu_pwroff();
return ret;
}
int rpu_disable(void)
{
int ret;
ret = rpu_pwroff();
if (ret) {
goto out;
}
ret = rpu_gpio_remove();
if (ret) {
goto out;
}
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
ret = sr_gpio_remove();
if (ret) {
goto out;
}
#endif
qdev = NULL;
cfg = NULL;
out:
return ret;
}

View file

@ -0,0 +1,343 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing SPI device interface specific definitions for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#include <string.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/logging/log.h>
#include "qspi_if.h"
#include "spi_if.h"
LOG_MODULE_DECLARE(wifi_nrf_bus, CONFIG_WIFI_NRF70_BUS_LOG_LEVEL);
#define NRF7002_NODE DT_NODELABEL(nrf70)
static struct qspi_config *spim_config;
static const struct spi_dt_spec spi_spec =
SPI_DT_SPEC_GET(NRF7002_NODE, SPI_WORD_SET(8) | SPI_TRANSFER_MSB, 0);
static int spim_xfer_tx(unsigned int addr, void *data, unsigned int len)
{
int err;
uint8_t hdr[4] = {
0x02, /* PP opcode */
(((addr >> 16) & 0xFF) | 0x80),
(addr >> 8) & 0xFF,
(addr & 0xFF)
};
const struct spi_buf tx_buf[] = {
{.buf = hdr, .len = sizeof(hdr) },
{.buf = data, .len = len },
};
const struct spi_buf_set tx = { .buffers = tx_buf, .count = 2 };
err = spi_transceive_dt(&spi_spec, &tx, NULL);
return err;
}
static int spim_xfer_rx(unsigned int addr, void *data, unsigned int len, unsigned int discard_bytes)
{
uint8_t hdr[] = {
0x0b, /* FASTREAD opcode */
(addr >> 16) & 0xFF,
(addr >> 8) & 0xFF,
addr & 0xFF,
0 /* dummy byte */
};
const struct spi_buf tx_buf[] = {
{.buf = hdr, .len = sizeof(hdr) },
{.buf = NULL, .len = len },
};
const struct spi_buf_set tx = { .buffers = tx_buf, .count = 2 };
const struct spi_buf rx_buf[] = {
{.buf = NULL, .len = sizeof(hdr) + discard_bytes},
{.buf = data, .len = len },
};
const struct spi_buf_set rx = { .buffers = rx_buf, .count = 2 };
return spi_transceive_dt(&spi_spec, &tx, &rx);
}
int spim_read_reg(uint32_t reg_addr, uint8_t *reg_value)
{
int err;
uint8_t tx_buffer[6] = { reg_addr };
const struct spi_buf tx_buf = {
.buf = tx_buffer,
.len = sizeof(tx_buffer)
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};
uint8_t sr[6];
struct spi_buf rx_buf = {
.buf = &sr,
.len = sizeof(sr),
};
const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
err = spi_transceive_dt(&spi_spec, &tx, &rx);
LOG_DBG("err: %d -> %x %x %x %x %x %x", err, sr[0], sr[1], sr[2], sr[3], sr[4], sr[5]);
if (err == 0)
*reg_value = sr[1];
return err;
}
int spim_write_reg(uint32_t reg_addr, const uint8_t reg_value)
{
int err;
uint8_t tx_buffer[] = { reg_addr, reg_value };
const struct spi_buf tx_buf = { .buf = tx_buffer, .len = sizeof(tx_buffer) };
const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
err = spi_transceive_dt(&spi_spec, &tx, NULL);
if (err) {
LOG_ERR("SPI error: %d", err);
}
return err;
}
int spim_RDSR1(const struct device *dev, uint8_t *rdsr1)
{
uint8_t val = 0;
return spim_read_reg(0x1F, &val);
}
int spim_RDSR2(const struct device *dev, uint8_t *rdsr1)
{
uint8_t val = 0;
return spim_read_reg(0x2F, &val);
}
int spim_WRSR2(const struct device *dev, const uint8_t wrsr2)
{
return spim_write_reg(0x3F, wrsr2);
}
int _spim_wait_while_rpu_awake(void)
{
int ret;
uint8_t val = 0;
for (int ii = 0; ii < 10; ii++) {
ret = spim_read_reg(0x1F, &val);
LOG_DBG("RDSR1 = 0x%x", val);
if (!ret && (val & RPU_AWAKE_BIT)) {
break;
}
k_msleep(1);
}
if (ret || !(val & RPU_AWAKE_BIT)) {
LOG_ERR("RPU is not awake even after 10ms");
return -1;
}
return val;
}
/* Wait until RDSR2 confirms RPU_WAKEUP_NOW write is successful */
int spim_wait_while_rpu_wake_write(void)
{
int ret;
uint8_t val = 0;
for (int ii = 0; ii < 10; ii++) {
ret = spim_read_reg(0x2F, &val);
LOG_DBG("RDSR2 = 0x%x", val);
if (!ret && (val & RPU_WAKEUP_NOW)) {
break;
}
k_msleep(1);
}
if (ret || !(val & RPU_WAKEUP_NOW)) {
LOG_ERR("RPU wakeup write ACK failed even after 10ms");
return -1;
}
return ret;
}
int spim_cmd_rpu_wakeup(uint32_t data)
{
return spim_write_reg(0x3F, data);
}
unsigned int spim_cmd_sleep_rpu(void)
{
int err;
uint8_t tx_buffer[] = { 0x3f, 0x0 };
const struct spi_buf tx_buf = { .buf = tx_buffer, .len = sizeof(tx_buffer) };
const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
err = spi_transceive_dt(&spi_spec, &tx, NULL);
if (err) {
LOG_ERR("SPI error: %d", err);
}
return 0;
}
int spim_init(struct qspi_config *config)
{
if (!spi_is_ready_dt(&spi_spec)) {
LOG_ERR("Device %s is not ready", spi_spec.bus->name);
return -ENODEV;
}
spim_config = config;
k_sem_init(&spim_config->lock, 1, 1);
if (spi_spec.config.frequency >= MHZ(16)) {
spim_config->qspi_slave_latency = 1;
}
LOG_INF("SPIM %s: freq = %d MHz", spi_spec.bus->name,
spi_spec.config.frequency / MHZ(1));
LOG_INF("SPIM %s: latency = %d", spi_spec.bus->name, spim_config->qspi_slave_latency);
return 0;
}
int spim_deinit(void)
{
LOG_DBG("TODO : %s", __func__);
return 0;
}
static void spim_addr_check(unsigned int addr, const void *data, unsigned int len)
{
if ((addr % 4 != 0) || (((unsigned int)data) % 4 != 0) || (len % 4 != 0)) {
LOG_ERR("%s : Unaligned address %x %x %d %x %x", __func__, addr,
(unsigned int)data, (addr % 4 != 0), (((unsigned int)data) % 4 != 0),
(len % 4 != 0));
}
}
int spim_write(unsigned int addr, const void *data, int len)
{
int status;
spim_addr_check(addr, data, len);
addr |= spim_config->addrmask;
k_sem_take(&spim_config->lock, K_FOREVER);
status = spim_xfer_tx(addr, (void *)data, len);
k_sem_give(&spim_config->lock);
return status;
}
int spim_read(unsigned int addr, void *data, int len)
{
int status;
spim_addr_check(addr, data, len);
addr |= spim_config->addrmask;
k_sem_take(&spim_config->lock, K_FOREVER);
status = spim_xfer_rx(addr, data, len, 0);
k_sem_give(&spim_config->lock);
return status;
}
static int spim_hl_readw(unsigned int addr, void *data)
{
int status = -1;
k_sem_take(&spim_config->lock, K_FOREVER);
status = spim_xfer_rx(addr, data, 4, 4 * spim_config->qspi_slave_latency);
k_sem_give(&spim_config->lock);
return status;
}
int spim_hl_read(unsigned int addr, void *data, int len)
{
int count = 0;
spim_addr_check(addr, data, len);
while (count < (len / 4)) {
spim_hl_readw(addr + (4 * count), (char *)data + (4 * count));
count++;
}
return 0;
}
/* ------------------------------added for wifi utils -------------------------------- */
int spim_cmd_rpu_wakeup_fn(uint32_t data)
{
return spim_cmd_rpu_wakeup(data);
}
int spim_cmd_sleep_rpu_fn(void)
{
return spim_cmd_sleep_rpu();
}
int spim_wait_while_rpu_awake(void)
{
return _spim_wait_while_rpu_awake();
}
int spi_validate_rpu_wake_writecmd(void)
{
return spim_wait_while_rpu_wake_write();
}

View file

@ -0,0 +1,969 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing OS specific definitions for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/__assert.h>
#include "rpu_hw_if.h"
#include "shim.h"
#include "work.h"
#include "timer.h"
#include "osal_ops.h"
#include "qspi_if.h"
LOG_MODULE_REGISTER(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
struct zep_shim_intr_priv *intr_priv;
static void *zep_shim_mem_alloc(size_t size)
{
size_t size_aligned = ROUND_UP(size, 4);
return k_malloc(size_aligned);
}
static void *zep_shim_mem_zalloc(size_t size)
{
size_t size_aligned = ROUND_UP(size, 4);
return k_calloc(size_aligned, sizeof(char));
}
static void *zep_shim_mem_cpy(void *dest, const void *src, size_t count)
{
return memcpy(dest, src, count);
}
static void *zep_shim_mem_set(void *start, int val, size_t size)
{
return memset(start, val, size);
}
static int zep_shim_mem_cmp(const void *addr1,
const void *addr2,
size_t size)
{
return memcmp(addr1, addr2, size);
}
static unsigned int zep_shim_qspi_read_reg32(void *priv, unsigned long addr)
{
unsigned int val;
struct zep_shim_bus_qspi_priv *qspi_priv = priv;
struct qspi_dev *dev;
dev = qspi_priv->qspi_dev;
if (addr < 0x0C0000) {
dev->hl_read(addr, &val, 4);
} else {
dev->read(addr, &val, 4);
}
return val;
}
static void zep_shim_qspi_write_reg32(void *priv, unsigned long addr, unsigned int val)
{
struct zep_shim_bus_qspi_priv *qspi_priv = priv;
struct qspi_dev *dev;
dev = qspi_priv->qspi_dev;
dev->write(addr, &val, 4);
}
static void zep_shim_qspi_cpy_from(void *priv, void *dest, unsigned long addr, size_t count)
{
struct zep_shim_bus_qspi_priv *qspi_priv = priv;
struct qspi_dev *dev;
size_t count_aligned = ROUND_UP(count, 4);
dev = qspi_priv->qspi_dev;
if (addr < 0x0C0000) {
dev->hl_read(addr, dest, count_aligned);
} else {
dev->read(addr, dest, count_aligned);
}
}
static void zep_shim_qspi_cpy_to(void *priv, unsigned long addr, const void *src, size_t count)
{
struct zep_shim_bus_qspi_priv *qspi_priv = priv;
struct qspi_dev *dev;
size_t count_aligned = ROUND_UP(count, 4);
dev = qspi_priv->qspi_dev;
dev->write(addr, src, count_aligned);
}
static void *zep_shim_spinlock_alloc(void)
{
struct k_sem *lock = NULL;
lock = k_malloc(sizeof(*lock));
if (!lock) {
LOG_ERR("%s: Unable to allocate memory for spinlock", __func__);
}
return lock;
}
static void zep_shim_spinlock_free(void *lock)
{
k_free(lock);
}
static void zep_shim_spinlock_init(void *lock)
{
k_sem_init(lock, 1, 1);
}
static void zep_shim_spinlock_take(void *lock)
{
k_sem_take(lock, K_FOREVER);
}
static void zep_shim_spinlock_rel(void *lock)
{
k_sem_give(lock);
}
static void zep_shim_spinlock_irq_take(void *lock, unsigned long *flags)
{
k_sem_take(lock, K_FOREVER);
}
static void zep_shim_spinlock_irq_rel(void *lock, unsigned long *flags)
{
k_sem_give(lock);
}
static int zep_shim_pr_dbg(const char *fmt, va_list args)
{
static char buf[80];
vsnprintf(buf, sizeof(buf), fmt, args);
LOG_DBG("%s", buf);
return 0;
}
static int zep_shim_pr_info(const char *fmt, va_list args)
{
static char buf[80];
vsnprintf(buf, sizeof(buf), fmt, args);
LOG_INF("%s", buf);
return 0;
}
static int zep_shim_pr_err(const char *fmt, va_list args)
{
static char buf[256];
vsnprintf(buf, sizeof(buf), fmt, args);
LOG_ERR("%s", buf);
return 0;
}
struct nwb {
unsigned char *data;
unsigned char *tail;
int len;
int headroom;
void *next;
void *priv;
int iftype;
void *ifaddr;
void *dev;
int hostbuffer;
void *cleanup_ctx;
void (*cleanup_cb)();
unsigned char priority;
bool chksum_done;
};
static void *zep_shim_nbuf_alloc(unsigned int size)
{
struct nwb *nbuff;
nbuff = (struct nwb *)k_calloc(sizeof(struct nwb), sizeof(char));
if (!nbuff)
return NULL;
nbuff->priv = k_calloc(size, sizeof(char));
if (!nbuff->priv) {
k_free(nbuff);
return NULL;
}
nbuff->data = (unsigned char *)nbuff->priv;
nbuff->tail = nbuff->data;
nbuff->len = 0;
nbuff->headroom = 0;
nbuff->next = NULL;
return nbuff;
}
static void zep_shim_nbuf_free(void *nbuf)
{
k_free(((struct nwb *)nbuf)->priv);
k_free(nbuf);
}
static void zep_shim_nbuf_headroom_res(void *nbuf, unsigned int size)
{
struct nwb *nwb = (struct nwb *)nbuf;
nwb->data += size;
nwb->tail += size;
nwb->headroom += size;
}
static unsigned int zep_shim_nbuf_headroom_get(void *nbuf)
{
return ((struct nwb *)nbuf)->headroom;
}
static unsigned int zep_shim_nbuf_data_size(void *nbuf)
{
return ((struct nwb *)nbuf)->len;
}
static void *zep_shim_nbuf_data_get(void *nbuf)
{
return ((struct nwb *)nbuf)->data;
}
static void *zep_shim_nbuf_data_put(void *nbuf, unsigned int size)
{
struct nwb *nwb = (struct nwb *)nbuf;
unsigned char *data = nwb->tail;
nwb->tail += size;
nwb->len += size;
return data;
}
static void *zep_shim_nbuf_data_push(void *nbuf, unsigned int size)
{
struct nwb *nwb = (struct nwb *)nbuf;
nwb->data -= size;
nwb->headroom -= size;
nwb->len += size;
return nwb->data;
}
static void *zep_shim_nbuf_data_pull(void *nbuf, unsigned int size)
{
struct nwb *nwb = (struct nwb *)nbuf;
nwb->data += size;
nwb->headroom += size;
nwb->len -= size;
return nwb->data;
}
static unsigned char zep_shim_nbuf_get_priority(void *nbuf)
{
struct nwb *nwb = (struct nwb *)nbuf;
return nwb->priority;
}
static unsigned char zep_shim_nbuf_get_chksum_done(void *nbuf)
{
struct nwb *nwb = (struct nwb *)nbuf;
return nwb->chksum_done;
}
static void zep_shim_nbuf_set_chksum_done(void *nbuf, unsigned char chksum_done)
{
struct nwb *nwb = (struct nwb *)nbuf;
nwb->chksum_done = (bool)chksum_done;
}
#include <zephyr/net/ethernet.h>
#include <zephyr/net/net_core.h>
void *net_pkt_to_nbuf(struct net_pkt *pkt)
{
struct nwb *nbuff;
unsigned char *data;
unsigned int len;
len = net_pkt_get_len(pkt);
nbuff = zep_shim_nbuf_alloc(len + 100);
if (!nbuff) {
return NULL;
}
zep_shim_nbuf_headroom_res(nbuff, 100);
data = zep_shim_nbuf_data_put(nbuff, len);
net_pkt_read(pkt, data, len);
nbuff->priority = net_pkt_priority(pkt);
nbuff->chksum_done = (bool)net_pkt_is_chksum_done(pkt);
return nbuff;
}
void *net_pkt_from_nbuf(void *iface, void *frm)
{
struct net_pkt *pkt = NULL;
unsigned char *data;
unsigned int len;
struct nwb *nwb = frm;
if (!nwb) {
return NULL;
}
len = zep_shim_nbuf_data_size(nwb);
data = zep_shim_nbuf_data_get(nwb);
pkt = net_pkt_rx_alloc_with_buffer(iface, len, AF_UNSPEC, 0, K_MSEC(100));
if (!pkt) {
goto out;
}
if (net_pkt_write(pkt, data, len)) {
net_pkt_unref(pkt);
pkt = NULL;
goto out;
}
out:
zep_shim_nbuf_free(nwb);
return pkt;
}
#if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
void *net_raw_pkt_from_nbuf(void *iface, void *frm,
unsigned short raw_hdr_len,
void *raw_rx_hdr,
bool pkt_free)
{
struct net_pkt *pkt = NULL;
unsigned char *nwb_data;
unsigned char *data = NULL;
unsigned int nwb_len;
unsigned int total_len;
struct nwb *nwb = frm;
if (!nwb) {
LOG_ERR("%s: Received network buffer is NULL", __func__);
return NULL;
}
nwb_len = zep_shim_nbuf_data_size(nwb);
nwb_data = zep_shim_nbuf_data_get(nwb);
total_len = raw_hdr_len + nwb_len;
data = (unsigned char *)k_malloc(total_len);
if (!data) {
LOG_ERR("%s: Unable to allocate memory for sniffer data packet", __func__);
goto out;
}
pkt = net_pkt_rx_alloc_with_buffer(iface, total_len, AF_PACKET, ETH_P_ALL, K_MSEC(100));
if (!pkt) {
LOG_ERR("%s: Unable to allocate net packet buffer", __func__);
goto out;
}
memcpy(data, raw_rx_hdr, raw_hdr_len);
memcpy((data+raw_hdr_len), nwb_data, nwb_len);
if (net_pkt_write(pkt, data, total_len)) {
net_pkt_unref(pkt);
pkt = NULL;
goto out;
}
out:
if (data != NULL) {
k_free(data);
}
if (pkt_free) {
zep_shim_nbuf_free(nwb);
}
return pkt;
}
#endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
static void *zep_shim_llist_node_alloc(void)
{
struct zep_shim_llist_node *llist_node = NULL;
llist_node = k_calloc(sizeof(*llist_node), sizeof(char));
if (!llist_node) {
LOG_ERR("%s: Unable to allocate memory for linked list node", __func__);
return NULL;
}
sys_dnode_init(&llist_node->head);
return llist_node;
}
static void zep_shim_llist_node_free(void *llist_node)
{
k_free(llist_node);
}
static void *zep_shim_llist_node_data_get(void *llist_node)
{
struct zep_shim_llist_node *zep_llist_node = NULL;
zep_llist_node = (struct zep_shim_llist_node *)llist_node;
return zep_llist_node->data;
}
static void zep_shim_llist_node_data_set(void *llist_node, void *data)
{
struct zep_shim_llist_node *zep_llist_node = NULL;
zep_llist_node = (struct zep_shim_llist_node *)llist_node;
zep_llist_node->data = data;
}
static void *zep_shim_llist_alloc(void)
{
struct zep_shim_llist *llist = NULL;
llist = k_calloc(sizeof(*llist), sizeof(char));
if (!llist) {
LOG_ERR("%s: Unable to allocate memory for linked list", __func__);
}
return llist;
}
static void zep_shim_llist_free(void *llist)
{
k_free(llist);
}
static void zep_shim_llist_init(void *llist)
{
struct zep_shim_llist *zep_llist = NULL;
zep_llist = (struct zep_shim_llist *)llist;
sys_dlist_init(&zep_llist->head);
}
static void zep_shim_llist_add_node_tail(void *llist, void *llist_node)
{
struct zep_shim_llist *zep_llist = NULL;
struct zep_shim_llist_node *zep_node = NULL;
zep_llist = (struct zep_shim_llist *)llist;
zep_node = (struct zep_shim_llist_node *)llist_node;
sys_dlist_append(&zep_llist->head, &zep_node->head);
zep_llist->len += 1;
}
static void zep_shim_llist_add_node_head(void *llist, void *llist_node)
{
struct zep_shim_llist *zep_llist = NULL;
struct zep_shim_llist_node *zep_node = NULL;
zep_llist = (struct zep_shim_llist *)llist;
zep_node = (struct zep_shim_llist_node *)llist_node;
sys_dlist_prepend(&zep_llist->head, &zep_node->head);
zep_llist->len += 1;
}
static void *zep_shim_llist_get_node_head(void *llist)
{
struct zep_shim_llist_node *zep_head_node = NULL;
struct zep_shim_llist *zep_llist = NULL;
zep_llist = (struct zep_shim_llist *)llist;
if (!zep_llist->len) {
return NULL;
}
zep_head_node = (struct zep_shim_llist_node *)sys_dlist_peek_head(&zep_llist->head);
return zep_head_node;
}
static void *zep_shim_llist_get_node_nxt(void *llist, void *llist_node)
{
struct zep_shim_llist_node *zep_node = NULL;
struct zep_shim_llist_node *zep_nxt_node = NULL;
struct zep_shim_llist *zep_llist = NULL;
zep_llist = (struct zep_shim_llist *)llist;
zep_node = (struct zep_shim_llist_node *)llist_node;
zep_nxt_node = (struct zep_shim_llist_node *)sys_dlist_peek_next(&zep_llist->head,
&zep_node->head);
return zep_nxt_node;
}
static void zep_shim_llist_del_node(void *llist, void *llist_node)
{
struct zep_shim_llist_node *zep_node = NULL;
struct zep_shim_llist *zep_llist = NULL;
zep_llist = (struct zep_shim_llist *)llist;
zep_node = (struct zep_shim_llist_node *)llist_node;
sys_dlist_remove(&zep_node->head);
zep_llist->len -= 1;
}
static unsigned int zep_shim_llist_len(void *llist)
{
struct zep_shim_llist *zep_llist = NULL;
zep_llist = (struct zep_shim_llist *)llist;
return zep_llist->len;
}
static void *zep_shim_work_alloc(int type)
{
return work_alloc(type);
}
static void zep_shim_work_free(void *item)
{
return work_free(item);
}
static void zep_shim_work_init(void *item, void (*callback)(unsigned long data),
unsigned long data)
{
work_init(item, callback, data);
}
static void zep_shim_work_schedule(void *item)
{
work_schedule(item);
}
static void zep_shim_work_kill(void *item)
{
work_kill(item);
}
static unsigned long zep_shim_time_get_curr_us(void)
{
return k_uptime_get() * USEC_PER_MSEC;
}
static unsigned int zep_shim_time_elapsed_us(unsigned long start_time_us)
{
unsigned long curr_time_us = 0;
curr_time_us = zep_shim_time_get_curr_us();
return curr_time_us - start_time_us;
}
static enum nrf_wifi_status zep_shim_bus_qspi_dev_init(void *os_qspi_dev_ctx)
{
ARG_UNUSED(os_qspi_dev_ctx);
return NRF_WIFI_STATUS_SUCCESS;
}
static void zep_shim_bus_qspi_dev_deinit(void *priv)
{
struct zep_shim_bus_qspi_priv *qspi_priv = priv;
volatile struct qspi_dev *dev = qspi_priv->qspi_dev;
dev->deinit();
}
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;
struct qspi_dev *dev = qspi_dev();
int ret;
enum nrf_wifi_status status;
ret = rpu_init();
if (ret) {
LOG_ERR("%s: RPU init failed with error %d", __func__, ret);
return NULL;
}
status = dev->init(qspi_defconfig());
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: QSPI device init failed", __func__);
return NULL;
}
ret = rpu_enable();
if (ret) {
LOG_ERR("%s: RPU enable failed with error %d", __func__, ret);
return NULL;
}
zep_qspi_priv->qspi_dev = dev;
zep_qspi_priv->dev_added = true;
return zep_qspi_priv;
}
static void zep_shim_bus_qspi_dev_rem(void *priv)
{
struct zep_shim_bus_qspi_priv *qspi_priv = priv;
struct qspi_dev *dev = qspi_priv->qspi_dev;
ARG_UNUSED(dev);
/* TODO: Make qspi_dev a dynamic instance and remove it here */
rpu_disable();
}
static void *zep_shim_bus_qspi_init(void)
{
struct zep_shim_bus_qspi_priv *qspi_priv = NULL;
qspi_priv = k_calloc(sizeof(*qspi_priv), sizeof(char));
if (!qspi_priv) {
LOG_ERR("%s: Unable to allocate memory for qspi_priv", __func__);
goto out;
}
out:
return qspi_priv;
}
static void zep_shim_bus_qspi_deinit(void *os_qspi_priv)
{
struct zep_shim_bus_qspi_priv *qspi_priv = NULL;
qspi_priv = os_qspi_priv;
k_free(qspi_priv);
}
#ifdef CONFIG_NRF_WIFI_LOW_POWER
static int zep_shim_bus_qspi_ps_sleep(void *os_qspi_priv)
{
rpu_sleep();
return 0;
}
static int zep_shim_bus_qspi_ps_wake(void *os_qspi_priv)
{
rpu_wakeup();
return 0;
}
static int zep_shim_bus_qspi_ps_status(void *os_qspi_priv)
{
return rpu_sleep_status();
}
#endif /* CONFIG_NRF_WIFI_LOW_POWER */
static void zep_shim_bus_qspi_dev_host_map_get(void *os_qspi_dev_ctx,
struct nrf_wifi_osal_host_map *host_map)
{
if (!os_qspi_dev_ctx || !host_map) {
LOG_ERR("%s: Invalid parameters", __func__);
return;
}
host_map->addr = 0;
}
static void irq_work_handler(struct k_work *work)
{
int ret = 0;
ret = intr_priv->callbk_fn(intr_priv->callbk_data);
if (ret) {
LOG_ERR("%s: Interrupt callback failed", __func__);
}
}
extern struct k_work_q zep_wifi_intr_q;
static void zep_shim_irq_handler(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
ARG_UNUSED(cb);
ARG_UNUSED(pins);
k_work_schedule_for_queue(&zep_wifi_intr_q, &intr_priv->work, K_NO_WAIT);
}
static enum nrf_wifi_status zep_shim_bus_qspi_intr_reg(void *os_dev_ctx, void *callbk_data,
int (*callbk_fn)(void *callbk_data))
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
int ret = -1;
ARG_UNUSED(os_dev_ctx);
intr_priv = k_calloc(sizeof(*intr_priv), sizeof(char));
if (!intr_priv) {
LOG_ERR("%s: Unable to allocate memory for intr_priv", __func__);
goto out;
}
intr_priv->callbk_data = callbk_data;
intr_priv->callbk_fn = callbk_fn;
k_work_init_delayable(&intr_priv->work, irq_work_handler);
ret = rpu_irq_config(&intr_priv->gpio_cb_data, zep_shim_irq_handler);
if (ret) {
LOG_ERR("%s: request_irq failed", __func__);
k_free(intr_priv);
intr_priv = NULL;
goto out;
}
status = NRF_WIFI_STATUS_SUCCESS;
out:
return status;
}
static void zep_shim_bus_qspi_intr_unreg(void *os_qspi_dev_ctx)
{
struct k_work_sync sync;
int ret;
ARG_UNUSED(os_qspi_dev_ctx);
ret = rpu_irq_remove(&intr_priv->gpio_cb_data);
if (ret) {
LOG_ERR("%s: rpu_irq_remove failed", __func__);
return;
}
k_work_cancel_delayable_sync(&intr_priv->work, &sync);
k_free(intr_priv);
intr_priv = NULL;
}
#ifdef CONFIG_NRF_WIFI_LOW_POWER
static void *zep_shim_timer_alloc(void)
{
struct timer_list *timer = NULL;
timer = k_malloc(sizeof(*timer));
if (!timer)
LOG_ERR("%s: Unable to allocate memory for work", __func__);
return timer;
}
static void zep_shim_timer_init(void *timer, void (*callback)(unsigned long), unsigned long data)
{
((struct timer_list *)timer)->function = callback;
((struct timer_list *)timer)->data = data;
init_timer(timer);
}
static void zep_shim_timer_free(void *timer)
{
k_free(timer);
}
static void zep_shim_timer_schedule(void *timer, unsigned long duration)
{
mod_timer(timer, duration);
}
static void zep_shim_timer_kill(void *timer)
{
del_timer_sync(timer);
}
#endif /* CONFIG_NRF_WIFI_LOW_POWER */
static void zep_shim_assert(int test_val, int val, enum nrf_wifi_assert_op_type op, char *msg)
{
switch (op) {
case NRF_WIFI_ASSERT_EQUAL_TO:
NET_ASSERT(test_val == val, "%s", msg);
break;
case NRF_WIFI_ASSERT_NOT_EQUAL_TO:
NET_ASSERT(test_val != val, "%s", msg);
break;
case NRF_WIFI_ASSERT_LESS_THAN:
NET_ASSERT(test_val < val, "%s", msg);
break;
case NRF_WIFI_ASSERT_LESS_THAN_EQUAL_TO:
NET_ASSERT(test_val <= val, "%s", msg);
break;
case NRF_WIFI_ASSERT_GREATER_THAN:
NET_ASSERT(test_val > val, "%s", msg);
break;
case NRF_WIFI_ASSERT_GREATER_THAN_EQUAL_TO:
NET_ASSERT(test_val >= val, "%s", msg);
break;
default:
LOG_ERR("%s: Invalid assertion operation", __func__);
}
}
static unsigned int zep_shim_strlen(const void *str)
{
return strlen(str);
}
static const struct nrf_wifi_osal_ops nrf_wifi_os_zep_ops = {
.mem_alloc = zep_shim_mem_alloc,
.mem_zalloc = zep_shim_mem_zalloc,
.mem_free = k_free,
.mem_cpy = zep_shim_mem_cpy,
.mem_set = zep_shim_mem_set,
.mem_cmp = zep_shim_mem_cmp,
.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,
.spinlock_alloc = zep_shim_spinlock_alloc,
.spinlock_free = zep_shim_spinlock_free,
.spinlock_init = zep_shim_spinlock_init,
.spinlock_take = zep_shim_spinlock_take,
.spinlock_rel = zep_shim_spinlock_rel,
.spinlock_irq_take = zep_shim_spinlock_irq_take,
.spinlock_irq_rel = zep_shim_spinlock_irq_rel,
.log_dbg = zep_shim_pr_dbg,
.log_info = zep_shim_pr_info,
.log_err = zep_shim_pr_err,
.llist_node_alloc = zep_shim_llist_node_alloc,
.llist_node_free = zep_shim_llist_node_free,
.llist_node_data_get = zep_shim_llist_node_data_get,
.llist_node_data_set = zep_shim_llist_node_data_set,
.llist_alloc = zep_shim_llist_alloc,
.llist_free = zep_shim_llist_free,
.llist_init = zep_shim_llist_init,
.llist_add_node_tail = zep_shim_llist_add_node_tail,
.llist_add_node_head = zep_shim_llist_add_node_head,
.llist_get_node_head = zep_shim_llist_get_node_head,
.llist_get_node_nxt = zep_shim_llist_get_node_nxt,
.llist_del_node = zep_shim_llist_del_node,
.llist_len = zep_shim_llist_len,
.nbuf_alloc = zep_shim_nbuf_alloc,
.nbuf_free = zep_shim_nbuf_free,
.nbuf_headroom_res = zep_shim_nbuf_headroom_res,
.nbuf_headroom_get = zep_shim_nbuf_headroom_get,
.nbuf_data_size = zep_shim_nbuf_data_size,
.nbuf_data_get = zep_shim_nbuf_data_get,
.nbuf_data_put = zep_shim_nbuf_data_put,
.nbuf_data_push = zep_shim_nbuf_data_push,
.nbuf_data_pull = zep_shim_nbuf_data_pull,
.nbuf_get_priority = zep_shim_nbuf_get_priority,
.nbuf_get_chksum_done = zep_shim_nbuf_get_chksum_done,
.nbuf_set_chksum_done = zep_shim_nbuf_set_chksum_done,
.tasklet_alloc = zep_shim_work_alloc,
.tasklet_free = zep_shim_work_free,
.tasklet_init = zep_shim_work_init,
.tasklet_schedule = zep_shim_work_schedule,
.tasklet_kill = zep_shim_work_kill,
.sleep_ms = k_msleep,
.delay_us = k_usleep,
.time_get_curr_us = zep_shim_time_get_curr_us,
.time_elapsed_us = zep_shim_time_elapsed_us,
.bus_qspi_init = zep_shim_bus_qspi_init,
.bus_qspi_deinit = zep_shim_bus_qspi_deinit,
.bus_qspi_dev_add = zep_shim_bus_qspi_dev_add,
.bus_qspi_dev_rem = zep_shim_bus_qspi_dev_rem,
.bus_qspi_dev_init = zep_shim_bus_qspi_dev_init,
.bus_qspi_dev_deinit = zep_shim_bus_qspi_dev_deinit,
.bus_qspi_dev_intr_reg = zep_shim_bus_qspi_intr_reg,
.bus_qspi_dev_intr_unreg = zep_shim_bus_qspi_intr_unreg,
.bus_qspi_dev_host_map_get = zep_shim_bus_qspi_dev_host_map_get,
#ifdef CONFIG_NRF_WIFI_LOW_POWER
.timer_alloc = zep_shim_timer_alloc,
.timer_init = zep_shim_timer_init,
.timer_free = zep_shim_timer_free,
.timer_schedule = zep_shim_timer_schedule,
.timer_kill = zep_shim_timer_kill,
.bus_qspi_ps_sleep = zep_shim_bus_qspi_ps_sleep,
.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,
};
const struct nrf_wifi_osal_ops *get_os_ops(void)
{
return &nrf_wifi_os_zep_ops;
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing OS interface specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __SHIM_H__
#define __SHIM_H__
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/net/net_pkt.h>
/**
* struct zep_shim_bus_qspi_priv - Structure to hold context information for the Linux OS
* shim.
* @opriv: Pointer to OSAL context.
* @pcie_callbk_data: Callback data to be passed to the PCIe callback functions.
* @pcie_prb_callbk: The callback function to be called when a PCIe device
* has been probed.
* @pcie_rem_callbk: The callback function to be called when a PCIe device
* has been removed.
*
* This structure maintains the context information necessary for the operation
* of the Linux shim. Some of the elements of the structure need to be
* initialized during the initialization of the Linux shim while others need to
* be kept updated over the duration of the Linux shim operation.
*/
struct zep_shim_bus_qspi_priv {
void *qspi_dev;
bool dev_added;
bool dev_init;
};
struct zep_shim_intr_priv {
struct gpio_callback gpio_cb_data;
void *callbk_data;
int (*callbk_fn)(void *callbk_data);
struct k_work_delayable work;
};
struct zep_shim_llist_node {
sys_dnode_t head;
void *data;
};
struct zep_shim_llist {
sys_dlist_t head;
unsigned int len;
};
void *net_pkt_to_nbuf(struct net_pkt *pkt);
void *net_pkt_from_nbuf(void *iface, void *frm);
#if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
void *net_raw_pkt_from_nbuf(void *iface,
void *frm,
unsigned short raw_hdr_len,
void *raw_rx_hdr,
bool pkt_free);
#endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
#endif /* __SHIM_H__ */

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing timer specific definitons for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#include <stdio.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/gpio.h>
#include "timer.h"
static void timer_expiry_function(struct k_work *work)
{
struct timer_list *timer;
timer = (struct timer_list *)CONTAINER_OF(work, struct timer_list, work.work);
timer->function(timer->data);
}
void init_timer(struct timer_list *timer)
{
k_work_init_delayable(&timer->work, timer_expiry_function);
}
void mod_timer(struct timer_list *timer, int msec)
{
k_work_schedule(&timer->work, K_MSEC(msec));
}
void del_timer_sync(struct timer_list *timer)
{
k_work_cancel_delayable(&timer->work);
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing timer specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __TIMER_H__
#define __TIMER_H__
struct timer_list {
void (*function)(unsigned long data);
unsigned long data;
struct k_work_delayable work;
};
void init_timer(struct timer_list *timer);
void mod_timer(struct timer_list *timer, int msec);
void del_timer_sync(struct timer_list *timer);
#endif /* __TIMER_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,447 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing display scan specific definitions for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#include <stdlib.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include "util.h"
#include "fmac_api.h"
#include "fmac_tx.h"
#include "fmac_main.h"
#include "wifi_mgmt_scan.h"
LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
static enum nrf_wifi_band nrf_wifi_map_zep_band_to_rpu(enum wifi_frequency_bands zep_band)
{
switch (zep_band) {
case WIFI_FREQ_BAND_2_4_GHZ:
return NRF_WIFI_BAND_2GHZ;
case WIFI_FREQ_BAND_5_GHZ:
return NRF_WIFI_BAND_5GHZ;
default:
return NRF_WIFI_BAND_INVALID;
}
}
int nrf_wifi_disp_scan_zep(const struct device *dev, struct wifi_scan_params *params,
scan_result_cb_t cb)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct nrf_wifi_umac_scan_info *scan_info = NULL;
enum nrf_wifi_band band = NRF_WIFI_BAND_INVALID;
uint8_t band_flags = 0xFF;
uint8_t i = 0;
uint8_t j = 0;
uint8_t k = 0;
uint16_t num_scan_channels = 0;
int ret = -1;
vif_ctx_zep = dev->data;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
return ret;
}
if (vif_ctx_zep->if_op_state != NRF_WIFI_FMAC_IF_OP_STATE_UP) {
LOG_ERR("%s: Interface not UP", __func__);
return ret;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
if (!rpu_ctx_zep) {
LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
return ret;
}
k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
if (!rpu_ctx_zep->rpu_ctx) {
LOG_DBG("%s: RPU context not initialized", __func__);
goto out;
}
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
if (vif_ctx_zep->scan_in_progress) {
LOG_INF("%s: Scan already in progress", __func__);
ret = -EBUSY;
goto out;
}
if (params) {
band_flags &= (~(1 << WIFI_FREQ_BAND_2_4_GHZ));
#ifndef CONFIG_NRF70_2_4G_ONLY
band_flags &= (~(1 << WIFI_FREQ_BAND_5_GHZ));
#endif /* CONFIG_NRF70_2_4G_ONLY */
if (params->bands & band_flags) {
LOG_ERR("%s: Unsupported band(s) (0x%X)", __func__, params->bands);
ret = -EBUSY;
goto out;
}
for (j = 0; j < CONFIG_WIFI_MGMT_SCAN_CHAN_MAX_MANUAL; j++) {
if (!params->band_chan[j].channel) {
break;
}
num_scan_channels++;
}
}
vif_ctx_zep->disp_scan_cb = cb;
scan_info = k_calloc(sizeof(*scan_info) +
(num_scan_channels *
sizeof(scan_info->scan_params.center_frequency[0])),
sizeof(char));
if (!scan_info) {
LOG_ERR("%s: Unable to allocate memory for scan_info (size: %d bytes)",
__func__,
sizeof(*scan_info) + (num_scan_channels *
sizeof(scan_info->scan_params.center_frequency[0])));
goto out;
}
memset(scan_info, 0, sizeof(*scan_info) + (num_scan_channels *
sizeof(scan_info->scan_params.center_frequency[0])));
static uint8_t skip_local_admin_mac = IS_ENABLED(CONFIG_WIFI_NRF70_SKIP_LOCAL_ADMIN_MAC);
scan_info->scan_params.skip_local_admin_macs = skip_local_admin_mac;
scan_info->scan_reason = SCAN_DISPLAY;
if (params) {
if (params->scan_type == WIFI_SCAN_TYPE_PASSIVE) {
scan_info->scan_params.passive_scan = 1;
}
scan_info->scan_params.bands = params->bands;
if (params->dwell_time_active < 0) {
LOG_ERR("%s: Invalid dwell_time_active %d", __func__,
params->dwell_time_active);
goto out;
} else {
scan_info->scan_params.dwell_time_active = params->dwell_time_active;
}
if (params->dwell_time_passive < 0) {
LOG_ERR("%s: Invalid dwell_time_passive %d", __func__,
params->dwell_time_passive);
goto out;
} else {
scan_info->scan_params.dwell_time_passive = params->dwell_time_passive;
}
if ((params->max_bss_cnt < 0) ||
(params->max_bss_cnt > WIFI_MGMT_SCAN_MAX_BSS_CNT)) {
LOG_ERR("%s: Invalid max_bss_cnt %d", __func__,
params->max_bss_cnt);
goto out;
} else {
vif_ctx_zep->max_bss_cnt = params->max_bss_cnt;
}
for (i = 0; i < NRF_WIFI_SCAN_MAX_NUM_SSIDS; i++) {
if (!(params->ssids[i]) || !strlen(params->ssids[i])) {
break;
}
memcpy(scan_info->scan_params.scan_ssids[i].nrf_wifi_ssid,
params->ssids[i],
sizeof(scan_info->scan_params.scan_ssids[i].nrf_wifi_ssid));
scan_info->scan_params.scan_ssids[i].nrf_wifi_ssid_len =
strlen(scan_info->scan_params.scan_ssids[i].nrf_wifi_ssid);
scan_info->scan_params.num_scan_ssids++;
}
for (i = 0; i < CONFIG_WIFI_MGMT_SCAN_CHAN_MAX_MANUAL; i++) {
if (!params->band_chan[i].channel) {
break;
}
band = nrf_wifi_map_zep_band_to_rpu(params->band_chan[i].band);
if (band == NRF_WIFI_BAND_INVALID) {
LOG_ERR("%s: Unsupported band %d", __func__,
params->band_chan[i].band);
goto out;
}
scan_info->scan_params.center_frequency[k++] = nrf_wifi_utils_chan_to_freq(
fmac_dev_ctx->fpriv->opriv, band, params->band_chan[i].channel);
if (scan_info->scan_params.center_frequency[k - 1] == -1) {
LOG_ERR("%s: Invalid channel %d", __func__,
params->band_chan[i].channel);
goto out;
}
}
scan_info->scan_params.num_scan_channels = k;
}
vif_ctx_zep->scan_res_cnt = 0;
status = nrf_wifi_fmac_scan(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, scan_info);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: nrf_wifi_fmac_scan failed", __func__);
goto out;
}
vif_ctx_zep->scan_type = SCAN_DISPLAY;
vif_ctx_zep->scan_in_progress = true;
k_work_schedule(&vif_ctx_zep->scan_timeout_work,
K_SECONDS(CONFIG_WIFI_NRF70_SCAN_TIMEOUT_S));
ret = 0;
out:
if (scan_info) {
k_free(scan_info);
}
k_mutex_unlock(&vif_ctx_zep->vif_lock);
return ret;
}
enum nrf_wifi_status nrf_wifi_disp_scan_res_get_zep(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
if (!rpu_ctx_zep) {
LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
return NRF_WIFI_STATUS_FAIL;
}
k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
if (!rpu_ctx_zep->rpu_ctx) {
LOG_DBG("%s: RPU context not initialized", __func__);
goto out;
}
status = nrf_wifi_fmac_scan_res_get(rpu_ctx_zep->rpu_ctx,
vif_ctx_zep->vif_idx,
SCAN_DISPLAY);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("%s: nrf_wifi_fmac_scan failed", __func__);
goto out;
}
status = NRF_WIFI_STATUS_SUCCESS;
out:
k_mutex_unlock(&vif_ctx_zep->vif_lock);
return status;
}
static inline enum wifi_mfp_options drv_to_wifi_mgmt_mfp(unsigned char mfp_flag)
{
if (!mfp_flag)
return WIFI_MFP_DISABLE;
if (mfp_flag & NRF_WIFI_MFP_REQUIRED)
return WIFI_MFP_REQUIRED;
if (mfp_flag & NRF_WIFI_MFP_CAPABLE)
return WIFI_MFP_OPTIONAL;
return WIFI_MFP_UNKNOWN;
}
static inline enum wifi_security_type drv_to_wifi_mgmt(int drv_security_type)
{
switch (drv_security_type) {
case NRF_WIFI_OPEN:
return WIFI_SECURITY_TYPE_NONE;
case NRF_WIFI_WEP:
return WIFI_SECURITY_TYPE_WEP;
case NRF_WIFI_WPA:
return WIFI_SECURITY_TYPE_WPA_PSK;
case NRF_WIFI_WPA2:
return WIFI_SECURITY_TYPE_PSK;
case NRF_WIFI_WPA2_256:
return WIFI_SECURITY_TYPE_PSK_SHA256;
case NRF_WIFI_WPA3:
return WIFI_SECURITY_TYPE_SAE;
case NRF_WIFI_WAPI:
return WIFI_SECURITY_TYPE_WAPI;
case NRF_WIFI_EAP:
return WIFI_SECURITY_TYPE_EAP;
default:
return WIFI_SECURITY_TYPE_UNKNOWN;
}
}
void nrf_wifi_event_proc_disp_scan_res_zep(void *vif_ctx,
struct nrf_wifi_umac_event_new_scan_display_results *scan_res,
unsigned int event_len,
bool more_res)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
struct umac_display_results *r = NULL;
struct wifi_scan_result res;
uint16_t max_bss_cnt = 0;
unsigned int i = 0;
scan_result_cb_t cb = NULL;
vif_ctx_zep = vif_ctx;
cb = (scan_result_cb_t)vif_ctx_zep->disp_scan_cb;
/* Delayed event (after scan timeout) or rogue event after scan done */
if (!cb) {
return;
}
max_bss_cnt = vif_ctx_zep->max_bss_cnt ?
vif_ctx_zep->max_bss_cnt : CONFIG_NRF_WIFI_SCAN_MAX_BSS_CNT;
for (i = 0; i < scan_res->event_bss_count; i++) {
/* Limit the scan results to the configured maximum */
if ((max_bss_cnt > 0) &&
(vif_ctx_zep->scan_res_cnt >= max_bss_cnt)) {
break;
}
memset(&res, 0x0, sizeof(res));
r = &scan_res->display_results[i];
res.ssid_length = MIN(sizeof(res.ssid), r->ssid.nrf_wifi_ssid_len);
res.band = r->nwk_band;
res.channel = r->nwk_channel;
res.security = drv_to_wifi_mgmt(r->security_type);
res.mfp = drv_to_wifi_mgmt_mfp(r->mfp_flag);
memcpy(res.ssid,
r->ssid.nrf_wifi_ssid,
res.ssid_length);
memcpy(res.mac, r->mac_addr, NRF_WIFI_ETH_ADDR_LEN);
res.mac_length = NRF_WIFI_ETH_ADDR_LEN;
if (r->signal.signal_type == NRF_WIFI_SIGNAL_TYPE_MBM) {
int val = (r->signal.signal.mbm_signal);
res.rssi = (val / 100);
} else if (r->signal.signal_type == NRF_WIFI_SIGNAL_TYPE_UNSPEC) {
res.rssi = (r->signal.signal.unspec_signal);
}
vif_ctx_zep->disp_scan_cb(vif_ctx_zep->zep_net_if_ctx,
0,
&res);
vif_ctx_zep->scan_res_cnt++;
/* NET_MGMT dropping events if too many are queued */
k_yield();
}
if (more_res == false) {
vif_ctx_zep->disp_scan_cb(vif_ctx_zep->zep_net_if_ctx, 0, NULL);
vif_ctx_zep->scan_in_progress = false;
vif_ctx_zep->disp_scan_cb = NULL;
k_work_cancel_delayable(&vif_ctx_zep->scan_timeout_work);
}
}
#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS
void nrf_wifi_rx_bcn_prb_resp_frm(void *vif_ctx,
void *nwb,
unsigned short frequency,
signed short signal)
{
struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = vif_ctx;
struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
struct wifi_raw_scan_result bcn_prb_resp_info;
int frame_length = 0;
int val = signal;
vif_ctx_zep = vif_ctx;
if (!vif_ctx_zep) {
LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
return;
}
if (!vif_ctx_zep->scan_in_progress) {
/*LOG_INF("%s: Scan not in progress : raw scan data not available", __func__);*/
return;
}
rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
if (!rpu_ctx_zep) {
LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
return;
}
k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
if (!rpu_ctx_zep->rpu_ctx) {
LOG_DBG("%s: RPU context not initialized", __func__);
goto out;
}
fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
frame_length = nrf_wifi_osal_nbuf_data_size(fmac_dev_ctx->fpriv->opriv,
nwb);
if (frame_length > CONFIG_WIFI_MGMT_RAW_SCAN_RESULT_LENGTH) {
nrf_wifi_osal_mem_cpy(fmac_dev_ctx->fpriv->opriv,
&bcn_prb_resp_info.data,
nrf_wifi_osal_nbuf_data_get(
fmac_dev_ctx->fpriv->opriv,
nwb),
CONFIG_WIFI_MGMT_RAW_SCAN_RESULT_LENGTH);
} else {
nrf_wifi_osal_mem_cpy(fmac_dev_ctx->fpriv->opriv,
&bcn_prb_resp_info.data,
nrf_wifi_osal_nbuf_data_get(
fmac_dev_ctx->fpriv->opriv,
nwb),
frame_length);
}
bcn_prb_resp_info.rssi = MBM_TO_DBM(val);
bcn_prb_resp_info.frequency = frequency;
bcn_prb_resp_info.frame_length = frame_length;
wifi_mgmt_raise_raw_scan_result_event(vif_ctx_zep->zep_net_if_ctx,
&bcn_prb_resp_info);
out:
k_mutex_unlock(&vif_ctx_zep->vif_lock);
}
#endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/* @file
* @brief nRF Wi-Fi radio-test mode shell module
*/
#include <zephyr/kernel.h>
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/shell/shell.h>
#include <zephyr/init.h>
#include <ctype.h>
#include <host_rpu_sys_if.h>
#include <fmac_structs.h>
#include <queue.h>
struct nrf_wifi_ctx_zep_rt {
struct nrf_wifi_fmac_priv *fmac_priv;
struct rpu_conf_params conf_params;
};

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief File containing work specific definitions for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#include <zephyr/sys/printk.h>
#include <zephyr/logging/log.h>
#include "work.h"
LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
K_THREAD_STACK_DEFINE(bh_wq_stack_area, CONFIG_NRF70_BH_WQ_STACK_SIZE);
struct k_work_q zep_wifi_bh_q;
K_THREAD_STACK_DEFINE(irq_wq_stack_area, CONFIG_NRF70_IRQ_WQ_STACK_SIZE);
struct k_work_q zep_wifi_intr_q;
#ifdef CONFIG_NRF70_TX_DONE_WQ_ENABLED
K_THREAD_STACK_DEFINE(tx_done_wq_stack_area, CONFIG_NRF70_TX_DONE_WQ_STACK_SIZE);
struct k_work_q zep_wifi_tx_done_q;
#endif /* CONFIG_NRF70_TX_DONE_WQ_ENABLED */
#ifdef CONFIG_NRF70_RX_WQ_ENABLED
K_THREAD_STACK_DEFINE(rx_wq_stack_area, CONFIG_NRF70_RX_WQ_STACK_SIZE);
struct k_work_q zep_wifi_rx_q;
#endif /* CONFIG_NRF70_RX_WQ_ENABLED */
struct zep_work_item zep_work_item[CONFIG_NRF70_WORKQ_MAX_ITEMS];
int get_free_work_item_index(void)
{
int i;
for (i = 0; i < CONFIG_NRF70_WORKQ_MAX_ITEMS; i++) {
if (zep_work_item[i].in_use)
continue;
return i;
}
return -1;
}
void workqueue_callback(struct k_work *work)
{
struct zep_work_item *item = CONTAINER_OF(work, struct zep_work_item, work);
item->callback(item->data);
}
struct zep_work_item *work_alloc(enum zep_work_type type)
{
int free_work_index = get_free_work_item_index();
if (free_work_index < 0) {
LOG_ERR("%s: Reached maximum work items", __func__);
return NULL;
}
zep_work_item[free_work_index].in_use = true;
zep_work_item[free_work_index].type = type;
return &zep_work_item[free_work_index];
}
static int workqueue_init(void)
{
k_work_queue_init(&zep_wifi_bh_q);
k_work_queue_start(&zep_wifi_bh_q,
bh_wq_stack_area,
K_THREAD_STACK_SIZEOF(bh_wq_stack_area),
CONFIG_NRF70_BH_WQ_PRIORITY,
NULL);
k_thread_name_set(&zep_wifi_bh_q.thread, "nrf70_bh_wq");
k_work_queue_init(&zep_wifi_intr_q);
k_work_queue_start(&zep_wifi_intr_q,
irq_wq_stack_area,
K_THREAD_STACK_SIZEOF(irq_wq_stack_area),
CONFIG_NRF70_IRQ_WQ_PRIORITY,
NULL);
k_thread_name_set(&zep_wifi_intr_q.thread, "nrf70_intr_wq");
#ifdef CONFIG_NRF70_TX_DONE_WQ_ENABLED
k_work_queue_init(&zep_wifi_tx_done_q);
k_work_queue_start(&zep_wifi_tx_done_q,
tx_done_wq_stack_area,
K_THREAD_STACK_SIZEOF(tx_done_wq_stack_area),
CONFIG_NRF70_TX_DONE_WQ_PRIORITY,
NULL);
k_thread_name_set(&zep_wifi_tx_done_q.thread, "nrf70_tx_done_wq");
#endif /* CONFIG_NRF70_TX_DONE_WQ_ENABLED */
#ifdef CONFIG_NRF70_RX_WQ_ENABLED
k_work_queue_init(&zep_wifi_rx_q);
k_work_queue_start(&zep_wifi_rx_q,
rx_wq_stack_area,
K_THREAD_STACK_SIZEOF(rx_wq_stack_area),
CONFIG_NRF70_RX_WQ_PRIORITY,
NULL);
k_thread_name_set(&zep_wifi_rx_q.thread, "nrf70_rx_wq");
#endif /* CONFIG_NRF70_RX_WQ_ENABLED */
return 0;
}
void work_init(struct zep_work_item *item, void (*callback)(unsigned long),
unsigned long data)
{
item->callback = callback;
item->data = data;
k_work_init(&item->work, workqueue_callback);
}
void work_schedule(struct zep_work_item *item)
{
if (item->type == ZEP_WORK_TYPE_IRQ)
k_work_submit_to_queue(&zep_wifi_intr_q, &item->work);
else if (item->type == ZEP_WORK_TYPE_BH)
k_work_submit_to_queue(&zep_wifi_bh_q, &item->work);
#ifdef CONFIG_NRF70_TX_DONE_WQ_ENABLED
else if (item->type == ZEP_WORK_TYPE_TX_DONE)
k_work_submit_to_queue(&zep_wifi_tx_done_q, &item->work);
#endif /* CONFIG_NRF70_TX_DONE_WQ_ENABLED */
#ifdef CONFIG_NRF70_RX_WQ_ENABLED
else if (item->type == ZEP_WORK_TYPE_RX)
k_work_submit_to_queue(&zep_wifi_rx_q, &item->work);
#endif /* CONFIG_NRF70_RX_WQ_ENABLED */
}
void work_kill(struct zep_work_item *item)
{
/* TODO: Based on context, use _sync version */
k_work_cancel(&item->work);
}
void work_free(struct zep_work_item *item)
{
item->in_use = 0;
}
SYS_INIT(workqueue_init, POST_KERNEL, 0);

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Header containing work specific declarations for the
* Zephyr OS layer of the Wi-Fi driver.
*/
#ifndef __WORK_H__
#define __WORK_H__
extern struct k_work_q zep_wifi_bh_q;
enum zep_work_type {
ZEP_WORK_TYPE_BH,
ZEP_WORK_TYPE_IRQ,
ZEP_WORK_TYPE_TX_DONE,
ZEP_WORK_TYPE_RX,
};
struct zep_work_item {
bool in_use;
struct k_work work;
unsigned long data;
void (*callback)(unsigned long data);
enum zep_work_type type;
};
struct zep_work_item *work_alloc(enum zep_work_type);
void work_init(struct zep_work_item *work, void (*callback)(unsigned long callbk_data),
unsigned long data);
void work_schedule(struct zep_work_item *work);
void work_kill(struct zep_work_item *work);
void work_free(struct zep_work_item *work);
#endif /* __WORK_H__ */

File diff suppressed because it is too large Load diff

View file

@ -907,6 +907,7 @@ flagged.
"MYFEATURE",
"MY_DRIVER_0",
"NORMAL_SLEEP", # #defined by RV32M1 in ext/
"NRF_WIFI_FW_BIN", # Directly passed from CMakeLists.txt
"OPT",
"OPT_0",
"PEDO_THS_MIN",