diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c24eb2e290cc..6c70b8877702 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1951,6 +1951,29 @@ Release Notes: labels: - "area: Wi-Fi" +"Drivers: Wi-Fi as nRF Wi-Fi": + status: maintained + maintainers: + - krish2718 + - jukkar + collaborators: + - sachinthegreen + 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: @@ -4315,6 +4338,11 @@ West: collaborators: - hubertmis - nordic-krch + - krish2718 + - sachinthegreen + - udaynordic + - rajb9 + - srkanordic files: - modules/hal_nordic/ labels: diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml index 1fb5a0398752..528846422f09 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml @@ -22,3 +22,7 @@ supported: - spi - watchdog - usbd +testing: + default: true + ignore_tags: + - ci_samples_wifi diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml index 9213c49fdd7b..4f415b266d2c 100644 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml @@ -21,3 +21,7 @@ supported: - spi - watchdog - i2s +testing: + default: true + ignore_tags: + - ci_samples_wifi diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.yaml b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.yaml index 460803eaa53d..b38fd67619a5 100644 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.yaml +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.yaml @@ -20,3 +20,7 @@ supported: - watchdog - adc - i2s +testing: + default: true + ignore_tags: + - ci_samples_wifi diff --git a/boards/nordic/nrf7002dk/CMakeLists.txt b/boards/nordic/nrf7002dk/CMakeLists.txt new file mode 100644 index 000000000000..db20255712bc --- /dev/null +++ b/boards/nordic/nrf7002dk/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if((CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP OR + CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NS OR + CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001 OR + CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS) AND + CONFIG_BOARD_ENABLE_CPUNET) + zephyr_library() + zephyr_library_sources(nrf5340_cpunet_reset.c) +endif() diff --git a/boards/nordic/nrf7002dk/Kconfig b/boards/nordic/nrf7002dk/Kconfig new file mode 100644 index 000000000000..4bd84612e7a9 --- /dev/null +++ b/boards/nordic/nrf7002dk/Kconfig @@ -0,0 +1,71 @@ +# nRF5340 DK board configuration + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config IPM_NRFX + default IPM + +config MBOX_NRFX_IPC + default MBOX + +if BOARD_NRF7002DK_NRF5340_CPUAPP || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NS || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001 || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS + +config BT_HCI_IPC + default y if BT + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 4096 if BT_HCI_IPC + +config BOARD_ENABLE_CPUNET + bool "nRF53 Network MCU" + select SOC_NRF_GPIO_FORWARDER_FOR_NRF5340 if \ + $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_GPIO_FORWARDER)) + help + This option enables releasing the Network 'force off' signal, which + as a consequence will power up the Network MCU during system boot. + Additionally, the option allocates GPIO pins that will be used by UARTE + of the Network MCU. + Note: GPIO pin allocation can only be configured by the secure Application + MCU firmware, so when this option is used with the non-secure version of + the board, the application needs to take into consideration, that the + secure firmware image must already have configured GPIO allocation for the + Network MCU. + default y if (BT || NRF_802154_SER_HOST) + +config DOMAIN_CPUNET_BOARD + string + default "nrf7002dk/nrf5340/cpunet" + depends on BOARD_ENABLE_CPUNET + help + The board which will be used for CPUNET domain when creating a multi + image application where one or more images should be located on + another board. For example hci_ipc on the nRF5340_cpunet for + Bluetooth applications. + +endif + +if BOARD_NRF7002DK_NRF5340_CPUNET + +config BT_CTLR + default y if BT + +config BT_ECC + default y if BT + +config DOMAIN_CPUAPP_BOARD + string + default "nrf7002dk/nrf5340/cpuapp" if BOARD_NRF7002DK_NRF5340_CPUAPP + default "nrf7002dk/nrf5340/cpuapp/ns" if BOARD_NRF7002DK_NRF5340_CPUAPP_NS + default "nrf7002dk/nrf5340/cpuapp/nrf7001" if BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001 + default "nrf7002dk/nrf5340/cpuapp/nrf7001/ns" if BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS + help + The board which will be used for CPUAPP domain when creating a multi + image application where one or more images should be located on + another board. + +endif diff --git a/boards/nordic/nrf7002dk/Kconfig.defconfig b/boards/nordic/nrf7002dk/Kconfig.defconfig new file mode 100644 index 000000000000..a6357ae50b2a --- /dev/null +++ b/boards/nordic/nrf7002dk/Kconfig.defconfig @@ -0,0 +1,76 @@ +# nRF5340 DK nRF5340 board configuration + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NRF7002DK_NRF5340_CPUAPP || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NS || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001 || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS + +# By default, if we build for a Non-Secure version of the board, +# force building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y if BOARD_NRF7002DK_NRF5340_CPUAPP_NS || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS + +if BUILD_WITH_TFM + +# By default, if we build with TF-M, instruct build system to +# flash the combined TF-M (Secure) & Zephyr (Non Secure) image +config TFM_FLASH_MERGED_BINARY + bool + default y + +endif # BUILD_WITH_TFM + +# Code Partition: +# +# For the secure version of the board the firmware is linked at the beginning +# of the flash, or into the code-partition defined in DT if it is intended to +# be loaded by MCUboot. If the secure firmware is to be combined with a non- +# secure image (TRUSTED_EXECUTION_SECURE=y), the secure FW image shall always +# be restricted to the size of its code partition. +# +# For the non-secure version of the board, the firmware +# must be linked into the code-partition (non-secure) defined in DT, regardless. +# Apply this configuration below by setting the Kconfig symbols used by +# the linker according to the information extracted from DT partitions. + +# SRAM Partition: +# +# If the secure firmware is to be combined with a non-secure image +# (TRUSTED_EXECUTION_SECURE=y), the secure FW image SRAM shall always +# be restricted to the secure image SRAM partition (sram-secure-partition). +# Otherwise (if TRUSTED_EXECUTION_SECURE is not set) the whole zephyr,sram +# may be used by the image. +# +# For the non-secure version of the board, the firmware image SRAM is +# always restricted to the allocated non-secure SRAM partition. +# +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition +DT_CHOSEN_Z_SRAM_PARTITION := zephyr,sram-secure-partition + +if (BOARD_NRF7002DK_NRF5340_CPUAPP || BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001) && \ + TRUSTED_EXECUTION_SECURE + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +config SRAM_SIZE + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_SRAM_PARTITION),0,K) + +endif + +if BOARD_NRF7002DK_NRF5340_CPUAPP_NS || BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS + +config FLASH_LOAD_OFFSET + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +endif + +endif diff --git a/boards/nordic/nrf7002dk/Kconfig.nrf7002dk b/boards/nordic/nrf7002dk/Kconfig.nrf7002dk new file mode 100644 index 000000000000..91f52ee6f08c --- /dev/null +++ b/boards/nordic/nrf7002dk/Kconfig.nrf7002dk @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF7002DK + select SOC_NRF5340_CPUNET_QKAA if BOARD_NRF7002DK_NRF5340_CPUNET + select SOC_NRF5340_CPUAPP_QKAA if BOARD_NRF7002DK_NRF5340_CPUAPP || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NS || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001 || \ + BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS diff --git a/boards/nordic/nrf7002dk/board.cmake b/boards/nordic/nrf7002dk/board.cmake new file mode 100644 index 000000000000..bea0dc92ea9c --- /dev/null +++ b/boards/nordic/nrf7002dk/board.cmake @@ -0,0 +1,25 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NS OR + CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS) + set(TFM_PUBLIC_KEY_FORMAT "full") +endif() + +if(CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP OR + CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NS OR + CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001 OR + CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP_NRF7001_NS) + board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") +endif() + +if(CONFIG_TFM_FLASH_MERGED_BINARY) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file "${CMAKE_BINARY_DIR}/zephyr/tfm_merged.hex") +endif() + +if(CONFIG_BOARD_NRF7002DK_NRF5340_CPUNET) + board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") +endif() + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/nordic/nrf7002dk/board.yml b/boards/nordic/nrf7002dk/board.yml new file mode 100644 index 000000000000..ca94d73429e9 --- /dev/null +++ b/boards/nordic/nrf7002dk/board.yml @@ -0,0 +1,12 @@ +board: + name: nrf7002dk + vendor: nordic + socs: + - name: nrf5340 + variants: + - name: ns + cpucluster: cpuapp + - name: nrf7001 + cpucluster: cpuapp + variants: + - name: ns diff --git a/boards/nordic/nrf7002dk/doc/img/nrf7002dk.jpg b/boards/nordic/nrf7002dk/doc/img/nrf7002dk.jpg new file mode 100644 index 000000000000..51d5572a13be Binary files /dev/null and b/boards/nordic/nrf7002dk/doc/img/nrf7002dk.jpg differ diff --git a/boards/nordic/nrf7002dk/doc/index.rst b/boards/nordic/nrf7002dk/doc/index.rst new file mode 100644 index 000000000000..5b25a7aa28fb --- /dev/null +++ b/boards/nordic/nrf7002dk/doc/index.rst @@ -0,0 +1,341 @@ +.. _nrf7002dk_nrf5340: + +nRF7002 DK +########## + +Overview +******** + +The nRF7002 DK (PCA10143) is a single-board development kit for evaluation and development on +the nRF7002, a Wi-Fi companion IC to Nordic Semiconductor's nRF5340 System-on-Chip (SoC) host +processor. It is certified for the Wi-Fi Alliance® `Wi-Fi Certification program`_ in the +Connectivity, Security, and Optimization categories. See `UG Wi-Fi certification`_ for detailed +information. + +The nRF7002 is an IEEE 802.11ax (Wi-Fi 6) compliant solution that implements the Wi-Fi physical +layer and Medium Access Control (MAC) layer protocols. It implements the nRF Wi-Fi driver +software on the nRF5340 host processor communicating over the QSPI bus. + +The nRF5340 host is a dual-core SoC based on the Arm® Cortex®-M33 architecture. +It has the following features: + +* A full-featured Arm Cortex-M33F core with DSP instructions, FPU, and Armv8-M Security Extension, + running at up to 128 MHz, referred to as the application core. +* A secondary Arm Cortex-M33 core, with a reduced feature set, running at a fixed 64 MHz, + referred to as the network core. + +The ``nrf7002dk/nrf5340/cpuapp`` board target provides support for the application core on the +nRF5340 SoC. The ``nrf7002dk/nrf5340/cpunet`` board target provides support for the network +core on the nRF5340 SoC. + +.. figure:: img/nrf7002dk.jpg + :align: center + :alt: nRF7002 DK + + nRF7002 DK (Credit: Nordic Semiconductor) + +More information about the board can be found at the +`nRF7002 DK website`_. +The `nRF7002 DK Product Specification`_ +contains the processor's information and the datasheet. + +Hardware +======== + +* nRF7002 DK: + The nRF7002 DK has two external oscillators. + + * The frequency of the slow clock is 32.768 kHz. + * The frequency of the main clock is 32 MHz. + +* Micro-USB 2.0 cable + +Supported features +------------------ + +The ``nrf7002dk/nrf5340/cpuapp`` board configuration supports the following hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| ADC | on-chip | adc | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| FLASH | on-chip | flash | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| RTC | on-chip | system clock | ++-----------+------------+----------------------+ +| RTT | Segger | console | ++-----------+------------+----------------------+ +| RADIO | nrf7002 | Wi-Fi 6 (802.11ax) | ++-----------+------------+----------------------+ +| QSPI | on-chip | qspi | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| SPU | on-chip | system protection | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ +| USB | on-chip | usb | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + +The ``nrf7002dk/nrf5340/cpunet`` board configuration supports the following hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| FLASH | on-chip | flash | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| RADIO | on-chip | Bluetooth, | +| | | ieee802154 | ++-----------+------------+----------------------+ +| RTC | on-chip | system clock | ++-----------+------------+----------------------+ +| RTT | Segger | console | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + +Other hardware features have not been enabled yet for this board. +See `nRF7002 DK Product Specification`_ +for a complete list of nRF7002 DK board hardware features. + +Connections and IOs +------------------- + +The connections and IOs supported by the development kit are listed in this section. + +LED +^^^ + +* **LED 1** (green) = **P1.06** +* **LED 2** (green) = **P1.07** + +Push buttons +^^^^^^^^^^^^ + +* **Button 1** = **SW1** = **P1.08** +* **Button 2** = **SW2** = **P1.09** +* **BOOT** = **SW5** = boot/reset + +Wi-Fi control +^^^^^^^^^^^^^ + +* BUCKEN = **P0.12** +* IOVDD CONTROL = **P0.31** +* HOST IRQ = **P0.23** +* COEX_REQ = **P0.28** +* COEX_STATUS0 = **P0.30** +* COEX_STATUS1 = **P0.29** +* COEX_GRANT = **P0.24** + +Security components +------------------- + +The following security components are available: + +* Implementation Defined Attribution Unit (`IDAU`_) on the application core. + + The IDAU is implemented with the System Protection Unit and is used to define + secure and non-secure memory maps. By default, the entire memory space + (Flash, SRAM, and peripheral address space) is defined to be secure-accessible only. + +* Secure boot. + +Programming and Debugging +************************* + +The nRF5340 application core supports the Armv8-M Security Extension. +Applications built for the ``nrf7002dk/nrf5340/cpuapp`` board boot by default in the +secure state. + +The nRF5340 network core does not support the Armv8-M Security Extension. +nRF5340 IDAU can configure bus accesses by the nRF5340 network core to have the secure +attribute set. This allows to build and run secure-only applications on the nRF5340 SoC. + +Building Secure/Non-Secure Zephyr applications with Arm |reg| TrustZone |reg| +============================================================================= + +Applications on the nRF5340 may contain a Secure and a Non-Secure firmware +image for the application core. The Secure image can be built using either +Zephyr or `Trusted Firmware M`_ (TF-M). Non-Secure firmware +images are always built using Zephyr. The two alternatives are described below. + +.. note:: + + By default, SPE for the nRF5340 application core is built using TF-M. + +Building the Secure firmware with TF-M +-------------------------------------- + +The process to build the Secure firmware image using TF-M and the Non-Secure +firmware image using Zephyr requires the following steps: + +1. Build the Non-Secure Zephyr application + for the application core using ``-DBOARD=nrf7002dk/nrf5340/cpuapp/ns``. + To invoke the building of TF-M the Zephyr build system requires the + Kconfig option ``BUILD_WITH_TFM`` to be enabled, which is done by + default when building Zephyr as a Non-Secure application. + The Zephyr build system will perform the following steps automatically: + + * Build the Non-Secure firmware image as a regular Zephyr application + * Build a TF-M (secure) firmware image + * Merge the output image binaries together + * Optionally build a bootloader image (MCUboot) + +.. note:: + + Depending on the TF-M configuration, an application DTS overlay may be + required, to adjust the Non-Secure image Flash and SRAM starting address + and sizes. + +2. Build the application firmware for the network core using + ``-DBOARD=nrf7002dk/nrf5340/cpunet``. + +Building the Secure firmware using Zephyr +----------------------------------------- + +The process to build the Secure and the Non-Secure firmware images +using Zephyr requires the following steps: + +1. Build the Secure Zephyr application for the application core + using ``-DBOARD=nrf7002dk/nrf5340/cpuapp`` and + ``CONFIG_TRUSTED_EXECUTION_SECURE=y`` and ``CONFIG_BUILD_WITH_TFM=n`` + in the application project configuration file. +2. Build the Non-Secure Zephyr application for the application core + using ``-DBOARD=nrf7002dk/nrf5340/cpuapp/ns``. +3. Merge the two binaries together. +4. Build the application firmware for the network core using + ``-DBOARD=nrf7002dk/nrf5340/cpunet``. + +When building a Secure/Non-Secure application for the nRF5340 application core, +the Secure application will have to set the IDAU (SPU) configuration to allow +Non-Secure access to all CPU resources utilized by the Non-Secure application +firmware. SPU configuration shall take place before jumping to the Non-Secure +application. + +Building a Secure only application +================================== + +Build the Zephyr app in the usual way (see :ref:`build_an_application` +and :ref:`application_run`), using ``-DBOARD=nrf7002dk/nrf5340/cpuapp`` for +the firmware running on the nRF5340 application core, and using +``-DBOARD=nrf7002dk/nrf5340/cpunet`` for the firmware running +on the nRF5340 network core. + +Flashing +======== + +Follow the instructions in the :ref:`nordic_segger` page to install +and configure all the necessary software. Further information can be +found in :ref:`nordic_segger_flashing`. Then you can build and flash +applications as usual (:ref:`build_an_application` and +:ref:`application_run` for more details). + +.. warning:: + + The nRF5340 has a flash read-back protection feature. When flash read-back + protection is active, you will need to recover the chip before reflashing. + If you are flashing with :ref:`west `, run + this command for more details on the related ``--recover`` option: + + .. code-block:: console + + west flash -H -r nrfjprog --skip-rebuild + +.. note:: + + Flashing and debugging applications on the nRF5340 DK requires + upgrading the nRF Command Line Tools to version 10.12.0. Further + information on how to install the nRF Command Line Tools can be + found in :ref:`nordic_segger_flashing`. + +Here is an example for the :ref:`hello_world` application running on the +nRF5340 application core. + +First, run your favorite terminal program to listen for output. + +.. code-block:: console + + $ minicom -D -b 115200 + +Replace :code:`` with the port where the board nRF7002 DK +can be found. For example, under Linux, :code:`/dev/ttyACM0`. + +Then build and flash the application in the usual way. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf7002dk/nrf5340/cpuapp + :goals: build flash + +Debugging +========= + +Refer to the :ref:`nordic_segger` page to learn about debugging Nordic +boards with a Segger IC. + +Next steps +********** + +You have now completed getting started with the nRF7002 DK. +See the following links for where to go next: + +* `Installation`_ and `Configuring and Building`_ documentation to install the + nRF Connect SDK and learn more about its development environment. +* `Developing with nRF70`_ documentation for more advanced topics related to the nRF70 Series. +* `Wi-Fi`_ documentation for information related to Wi-Fi protocol and Wi-Fi modes of operation. + +References +********** + +.. target-notes:: + +.. _Wi-Fi Certification program: + https://www.wi-fi.org/certification +.. _UG Wi-Fi certification: + https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/wifi/wifi_certification.html#ug-wifi-certification +.. _IDAU: + https://developer.arm.com/docs/100690/latest/attribution-units-sau-and-idau +.. _nRF7002 DK website: + https://www.nordicsemi.com/Products/Development-hardware/nrf7002-dk +.. _nRF7002 DK Product Specification: + https://docs.nordicsemi.com/bundle/ps_nrf5340/page/keyfeatures_html5.html +.. _Trusted Firmware M: + https://www.trustedfirmware.org/projects/tf-m/ +.. _Installation: + https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/installation.html#installation +.. _Configuring and Building: + https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/config_and_build/index.html#configuration-and-build +.. _Developing with nRF70: + https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/device_guides/nrf70/index.html#ug-nrf70-developing +.. _Wi-Fi: + https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/wifi/index.html#ug-wifi diff --git a/boards/nordic/nrf7002dk/nrf5340_cpuapp_common.dtsi b/boards/nordic/nrf7002dk/nrf5340_cpuapp_common.dtsi new file mode 100644 index 000000000000..c571d4b1f3b5 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf5340_cpuapp_common.dtsi @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "nrf5340_cpuapp_common_pinctrl.dtsi" +#include + +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,bt-hci = &bt_hci_ipc0; + nordic,802154-spinel-ipc = &ipc0; + zephyr,ieee802154 = &ieee802154; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + label = "Green LED 0"; + }; + led1: led_1 { + gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led0: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 4 0>, /* A0 */ + <1 0 &gpio0 5 0>, /* A1 */ + <2 0 &gpio0 6 0>, /* A2 */ + <3 0 &gpio0 7 0>, /* A3 */ + <4 0 &gpio0 25 0>, /* A4 */ + <5 0 &gpio0 26 0>, /* A5 */ + <6 0 &gpio1 0 0>, /* D0 */ + <7 0 &gpio1 1 0>, /* D1 */ + <8 0 &gpio1 4 0>, /* D2 */ + <9 0 &gpio1 5 0>, /* D3 */ + <10 0 &gpio1 6 0>, /* D4 */ + <11 0 &gpio1 7 0>, /* D5 */ + <12 0 &gpio1 8 0>, /* D6 */ + <13 0 &gpio1 9 0>, /* D7 */ + <14 0 &gpio1 10 0>, /* D8 */ + <15 0 &gpio1 11 0>, /* D9 */ + <16 0 &gpio1 12 0>, /* D10 */ + <17 0 &gpio1 13 0>, /* D11 */ + <18 0 &gpio1 14 0>, /* D12 */ + <19 0 &gpio1 15 0>, /* D13 */ + <20 0 &gpio1 2 0>, /* D14 */ + <21 0 &gpio1 3 0>; /* D15 */ + }; + + arduino_adc: analog-connector { + compatible = "arduino,uno-adc"; + #io-channel-cells = <1>; + io-channel-map = <0 &adc 0>, /* A0 = P0.4 = AIN0 */ + <1 &adc 1>, /* A1 = P0.5 = AIN1 */ + <2 &adc 2>, /* A2 = P0.6 = AIN2 */ + <3 &adc 3>, /* A3 = P0.7 = AIN3 */ + <4 &adc 4>, /* A4 = P0.25 = AIN4 */ + <5 &adc 5>; /* A5 = P0.26 = AIN5 */ + }; + + gpio_fwd: nrf-gpio-forwarder { + compatible = "nordic,nrf-gpio-forwarder"; + status = "okay"; + uart { + gpios = <&gpio1 1 0>, <&gpio1 0 0>, <&gpio1 5 0>, <&gpio1 4 0>; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + pwm-led0 = &pwm_led0; + sw0 = &button0; + sw1 = &button1; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + }; +}; + +&vregmain { + regulator-initial-mode = ; +}; + +&vregradio { + regulator-initial-mode = ; +}; + +&vregh { + status = "okay"; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +arduino_i2c: &i2c1 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c1_default>; + pinctrl-1 = <&i2c1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&spi4 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi4_default>; + pinctrl-1 = <&spi4_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + mx25r64: mx25r6435f@0 { + compatible = "jedec,spi-nor"; + status = "disabled"; + reg = <0>; + spi-max-frequency = <33000000>; + jedec-id = [c2 28 17]; + sfdp-bfp = [ + e5 20 f1 ff ff ff ff 03 44 eb 08 6b 08 3b 04 bb + ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 + 10 d8 00 ff 23 72 f5 00 82 ed 04 cc 44 83 68 44 + 30 b0 30 b0 f7 c4 d5 5c 00 be 29 ff f0 d0 ff ff + ]; + size = <67108864>; + has-dpd; + t-enter-dpd = <10000>; + t-exit-dpd = <5000>; + }; +}; + +&qspi { + status = "okay"; + pinctrl-0 = <&qspi_default>; + pinctrl-1 = <&qspi_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_serial: &uart1 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_spi: &spi3 { + compatible = "nordic,nrf-spim"; + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&flash0 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x00010000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + }; + slot0_ns_partition: partition@50000 { + label = "image-0-nonsecure"; + }; + slot1_partition: partition@80000 { + label = "image-1"; + }; + slot1_ns_partition: partition@c0000 { + label = "image-1-nonsecure"; + }; + /* 0xf0000 to 0xf7fff reserved for TF-M partitions */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 0x00008000>; + }; + }; +}; + +&ieee802154 { + status = "okay"; +}; + +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; +}; + +/ { + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_image: image@20000000 { + /* Zephyr image(s) memory */ + }; + + sram0_s: image_s@20000000 { + /* Secure image memory */ + }; + + sram0_ns: image_ns@20040000 { + /* Non-Secure image memory */ + }; + }; +}; + +/* Include partition configuration file */ +#include "nrf5340_cpuapp_common_partition_conf.dts" diff --git a/boards/nordic/nrf7002dk/nrf5340_cpuapp_common_partition_conf.dts b/boards/nordic/nrf7002dk/nrf5340_cpuapp_common_partition_conf.dts new file mode 100644 index 000000000000..b4fa353af3f1 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf5340_cpuapp_common_partition_conf.dts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Default Flash planning for nrf7002dk_nrf5340 CPUAPP (Application MCU). + * + * Zephyr build for nRF5340 with ARM TrustZone-M support, + * implies building Secure and Non-Secure Zephyr images. + * + * Secure image will be placed, by default, in flash0 + * (or in slot0, if MCUboot is present). + * Secure image will use sram0 for system memory. + * + * Non-Secure image will be placed in slot0_ns, and use + * sram0_ns for system memory. + * + * Note that the Secure image only requires knowledge of + * the beginning of the Non-Secure image (not its size). + */ + +&slot0_partition { + reg = <0x00010000 0x40000>; +}; + +&slot0_ns_partition { + reg = <0x00050000 0x30000>; +}; + +&slot1_partition { + reg = <0x00080000 0x40000>; +}; + +&slot1_ns_partition { + reg = <0x000c0000 0x30000>; +}; + +/* Default SRAM planning when building for nRF5340 with + * ARM TrustZone-M support + * - Lowest 256 kB SRAM allocated to Secure image (sram0_s) + * - Middle 192 kB allocated to Non-Secure image (sram0_ns) + * - Upper 64 kB SRAM allocated as Shared memory (sram0_shared) + * (see nrf5340_shared_sram_planning_conf.dts) + */ +&sram0_image { + reg = <0x20000000 DT_SIZE_K(448)>; +}; + +&sram0_s { + reg = <0x20000000 DT_SIZE_K(256)>; +}; + +&sram0_ns { + reg = <0x20040000 DT_SIZE_K(192)>; +}; + +/* Include shared RAM configuration file */ +#include "nrf5340_shared_sram_planning_conf.dts" diff --git a/boards/nordic/nrf7002dk/nrf5340_cpuapp_common_pinctrl.dtsi b/boards/nordic/nrf7002dk/nrf5340_cpuapp_common_pinctrl.dtsi new file mode 100644 index 000000000000..f04075f374d6 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf5340_cpuapp_common_pinctrl.dtsi @@ -0,0 +1,126 @@ +&pinctrl { + i2c1_default: i2c1_default { + group1 { + psels = , + ; + }; + }; + + i2c1_sleep: i2c1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + qspi_default: qspi_default { + group1 { + psels = , + , + , + , + , + ; + }; + }; + + qspi_sleep: qspi_sleep { + group1 { + psels = , + , + , + , + , + ; + low-power-enable; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi3_default: spi3_default { + group1 { + psels = , + , + ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + spi4_default: spi4_default { + group1 { + psels = , + , + ; + }; + }; + + spi4_sleep: spi4_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf5340_cpunet_reset.c b/boards/nordic/nrf7002dk/nrf5340_cpunet_reset.c new file mode 100644 index 000000000000..b86b571db4b7 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf5340_cpunet_reset.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +LOG_MODULE_REGISTER(nrf7002dk_nrf5340_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); + +#if defined(CONFIG_BT_CTLR_DEBUG_PINS_CPUAPP) +#include <../subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h> +#endif + +static void remoteproc_mgr_config(void) +{ +#if defined(CONFIG_BT_CTLR_DEBUG_PINS_CPUAPP) && \ + (!defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) || defined(CONFIG_BUILD_WITH_TFM)) + /* Route Bluetooth Controller Debug Pins */ + DEBUG_SETUP(); +#endif /* !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) || defined(CONFIG_BUILD_WITH_TFM) */ + +#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) + /* Retain nRF5340 Network MCU in Secure domain (bus + * accesses by Network MCU will have Secure attribute set). + */ + NRF_SPU->EXTDOMAIN[0].PERM = BIT(4); +#endif /* !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) */ +} + +static int remoteproc_mgr_boot(void) +{ + + /* Secure domain may configure permissions for the Network MCU. */ + remoteproc_mgr_config(); + +#if !defined(CONFIG_TRUSTED_EXECUTION_SECURE) + /* + * Building Zephyr with CONFIG_TRUSTED_EXECUTION_SECURE=y implies + * building also a Non-Secure image. The Non-Secure image will, in + * this case do the remainder of actions to properly configure and + * boot the Network MCU. + */ + + /* Release the Network MCU, 'Release force off signal' */ + nrf_reset_network_force_off(NRF_RESET, false); + + LOG_DBG("Network MCU released."); +#endif /* !CONFIG_TRUSTED_EXECUTION_SECURE */ + + return 0; +} + +SYS_INIT(remoteproc_mgr_boot, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/nordic/nrf7002dk/nrf5340_shared_sram_planning_conf.dts b/boards/nordic/nrf7002dk/nrf5340_shared_sram_planning_conf.dts new file mode 100644 index 000000000000..d009959d3f6b --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf5340_shared_sram_planning_conf.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Default shared SRAM planning when building for nRF5340. + * This file is included by both nRF5340 CPUAPP (Application MCU) + * and nRF5340 CPUNET (Network MCU). + * - 64 kB SRAM allocated as Shared memory (sram0_shared) + * - Region defined after the image SRAM of Application MCU + */ + +/ { + chosen { + /* shared memory reserved for the inter-processor communication */ + zephyr,ipc_shm = &sram0_shared; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_shared: memory@20070000 { + /* SRAM allocated to shared memory */ + reg = <0x20070000 0x10000>; + }; + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp.dts b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp.dts new file mode 100644 index 000000000000..fbe74a822240 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp.dts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf5340_cpuapp_common.dtsi" +#include "nrf7002dk_nrf5340_cpuapp_pinctrl.dtsi" + +/ { + model = "Nordic NRF7002 DK NRF5340 Application"; + compatible = "nordic,nrf7002-dk-nrf5340-cpuapp"; + + chosen { + zephyr,sram = &sram0_image; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + zephyr,sram-non-secure-partition = &sram0_ns; + zephyr,wifi = &wlan0; + }; +}; + +&qspi { + nrf70: nrf7002@1 { + compatible = "nordic,nrf7002-qspi"; + status = "okay"; + reg = <1>; + qspi-frequency = <24000000>; + qspi-quad-mode; + + #include "nrf70_common.dtsi" + #include "nrf70_common_coex.dtsi" + #include "nrf70_common_5g.dtsi" + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp.yaml b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp.yaml new file mode 100644 index 000000000000..9a6c65314424 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp.yaml @@ -0,0 +1,20 @@ +identifier: nrf7002dk/nrf5340/cpuapp +name: NRF7002-DK-NRF5340-application-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 448 +flash: 1024 +supported: + - gpio + - i2c + - i2s + - pwm + - watchdog + - usbd + - usb_device + - netif:openthread +vendor: nordic diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_defconfig b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_defconfig new file mode 100644 index 000000000000..24eee2849027 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_defconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable PINCTRL +CONFIG_PINCTRL=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001.dts b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001.dts new file mode 100644 index 000000000000..1d78dddbe68a --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001.dts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf5340_cpuapp_common.dtsi" +#include "nrf7002dk_nrf5340_cpuapp_pinctrl.dtsi" + +/ { + model = "Nordic NRF7002 DK NRF5340 Application"; + compatible = "nordic,nrf7002-dk-nrf5340-cpuapp"; + + chosen { + zephyr,sram = &sram0_image; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + zephyr,sram-non-secure-partition = &sram0_ns; + zephyr,wifi = &wlan0; + }; +}; + +&qspi { + nrf70: nrf7001@1 { + compatible = "nordic,nrf7001-qspi"; + status = "okay"; + reg = <1>; + qspi-frequency = <24000000>; + qspi-quad-mode; + + #include "nrf70_common.dtsi" + #include "nrf70_common_coex.dtsi" + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001.yaml b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001.yaml new file mode 100644 index 000000000000..e74ba0628aba --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001.yaml @@ -0,0 +1,20 @@ +identifier: nrf7002dk/nrf5340/cpuapp/nrf7001 +name: NRF7002-DK-NRF7001-NRF5340-application-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 448 +flash: 1024 +supported: + - gpio + - i2c + - i2s + - pwm + - watchdog + - usbd + - usb_device + - netif:openthread +vendor: nordic diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_defconfig b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_defconfig new file mode 100644 index 000000000000..870fdf32425b --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_defconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# enable GPIO +CONFIG_GPIO=y + +# enable PINCTRL +CONFIG_PINCTRL=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns.dts b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns.dts new file mode 100644 index 000000000000..cbbd46dff8be --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns.dts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf5340_cpuapp_common.dtsi" + +/ { + model = "Nordic NRF5340 DK NRF5340 Application"; + compatible = "nordic,nrf5340-dk-nrf5340-cpuapp"; + + chosen { + zephyr,sram = &sram0_ns; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_ns_partition; + zephyr,entropy = &psa_rng; + zephyr,wifi = &wlan0; + }; + + psa_rng: psa-rng { + compatible = "zephyr,psa-crypto-rng"; + status = "okay"; + }; +}; + +&qspi { + nrf70: nrf7001@1 { + compatible = "nordic,nrf7001-qspi"; + status = "okay"; + reg = <1>; + qspi-frequency = <24000000>; + qspi-quad-mode; + + #include "nrf70_common.dtsi" + #include "nrf70_common_coex.dtsi" + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns.yaml b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns.yaml new file mode 100644 index 000000000000..efdfcb7a0690 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns.yaml @@ -0,0 +1,23 @@ +identifier: nrf7002dk/nrf5340/cpuapp/nrf7001/ns +name: NRF7002-DK-NRF7001-NRF5340-application-MCU-Non-Secure +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 192 +flash: 192 +supported: + - gpio + - i2c + - pwm + - watchdog + - usbd + - usb_device + - netif:openthread +vendor: nordic +testing: + default: true + ignore_tags: + - ci_samples_wifi diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns_defconfig b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns_defconfig new file mode 100644 index 000000000000..c536aae767dc --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_nrf7001_ns_defconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# This Board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# enable GPIO +CONFIG_GPIO=y + +# enable PINCTRL +CONFIG_PINCTRL=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns.dts b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns.dts new file mode 100644 index 000000000000..26ef52132f0f --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns.dts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf5340_cpuapp_common.dtsi" + +/ { + model = "Nordic NRF5340 DK NRF5340 Application"; + compatible = "nordic,nrf5340-dk-nrf5340-cpuapp"; + + chosen { + zephyr,sram = &sram0_ns; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_ns_partition; + zephyr,entropy = &psa_rng; + zephyr,wifi = &wlan0; + }; + + psa_rng: psa-rng { + compatible = "zephyr,psa-crypto-rng"; + status = "okay"; + }; +}; + +&qspi { + nrf70: nrf7002@1 { + compatible = "nordic,nrf7002-qspi"; + status = "okay"; + reg = <1>; + qspi-frequency = <24000000>; + qspi-quad-mode; + + #include "nrf70_common.dtsi" + #include "nrf70_common_coex.dtsi" + #include "nrf70_common_5g.dtsi" + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns.yaml b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns.yaml new file mode 100644 index 000000000000..b2f57b48546a --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns.yaml @@ -0,0 +1,24 @@ +identifier: nrf7002dk/nrf5340/cpuapp/ns +name: NRF7002-DK-NRF5340-application-MCU-Non-Secure +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 192 +flash: 192 +supported: + - gpio + - i2c + - pwm + - watchdog + - usbd + - usb_device + - netif:openthread +vendor: nordic +testing: + default: true + ignore_tags: + - ci_build + - sysbuild diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns_defconfig b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns_defconfig new file mode 100644 index 000000000000..c5b2eaadc168 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_ns_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# This Board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# enable GPIO +CONFIG_GPIO=y + +# enable PINCTRL +CONFIG_PINCTRL=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_pinctrl.dtsi b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_pinctrl.dtsi new file mode 100644 index 000000000000..a7cde7241e5f --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpuapp_pinctrl.dtsi @@ -0,0 +1,18 @@ +&pinctrl { + spi2_default: spi2_default { + group1 { + psels = , + , + ; + }; + }; + + spi2_sleep: spi2_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet.dts b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet.dts new file mode 100644 index 000000000000..bf5a066f2fd7 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet.dts @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf7002dk_nrf5340_cpunet_pinctrl.dtsi" +#include + +/ { + model = "Nordic NRF7002 DK NRF5340 Network"; + compatible = "nordic,nrf7002-dk-nrf5340-cpunet"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + label = "Green LED 0"; + }; + led1: led_1 { + gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 4 0>, /* A0 */ + <1 0 &gpio0 5 0>, /* A1 */ + <2 0 &gpio0 6 0>, /* A2 */ + <3 0 &gpio0 7 0>, /* A3 */ + <4 0 &gpio0 25 0>, /* A4 */ + <5 0 &gpio0 26 0>, /* A5 */ + <6 0 &gpio1 0 0>, /* D0 */ + <7 0 &gpio1 1 0>, /* D1 */ + <8 0 &gpio1 4 0>, /* D2 */ + <9 0 &gpio1 5 0>, /* D3 */ + <10 0 &gpio1 6 0>, /* D4 */ + <11 0 &gpio1 7 0>, /* D5 */ + <12 0 &gpio1 8 0>, /* D6 */ + <13 0 &gpio1 9 0>, /* D7 */ + <14 0 &gpio1 10 0>, /* D8 */ + <15 0 &gpio1 11 0>, /* D9 */ + <16 0 &gpio1 12 0>, /* D10 */ + <17 0 &gpio1 13 0>, /* D11 */ + <18 0 &gpio1 14 0>, /* D12 */ + <19 0 &gpio1 15 0>, /* D13 */ + <20 0 &gpio1 2 0>, /* D14 */ + <21 0 &gpio1 3 0>; /* D15 */ + }; + + nrf70: coex { + status = "okay"; + compatible = "nordic,nrf70-coex"; + + #include "nrf70_common_coex.dtsi" + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + sw0 = &button0; + sw1 = &button1; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + }; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_serial: &uart0{}; + +arduino_i2c: &i2c0 { + compatible = "nordic,nrf-twim"; + /* Cannot be used together with uart0. */ + /* status = "okay"; */ + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_spi: &spi0 { + compatible = "nordic,nrf-spim"; + /* Cannot be used together with uart0. */ + /* status = "okay"; */ + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&flash1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0xc000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x17000>; + }; + slot1_partition: partition@23000 { + label = "image-1"; + reg = <0x00023000 0x17000>; + }; + storage_partition: partition@3a000 { + label = "storage"; + reg = <0x0003a000 0x6000>; + }; + }; +}; + +&ieee802154 { + status = "okay"; +}; + +/* Include shared RAM configuration file */ +#include "nrf5340_shared_sram_planning_conf.dts" diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet.yaml b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet.yaml new file mode 100644 index 000000000000..f04ef6cee84c --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet.yaml @@ -0,0 +1,14 @@ +identifier: nrf7002dk/nrf5340/cpunet +name: NRF7002-DK-NRF5340-network-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 64 +flash: 256 +supported: + - gpio + - watchdog +vendor: nordic diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet_defconfig b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet_defconfig new file mode 100644 index 000000000000..ec4a0acd7a86 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet_defconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# enable PINCTRL +CONFIG_PINCTRL=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet_pinctrl.dtsi b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet_pinctrl.dtsi new file mode 100644 index 000000000000..2e19d95f7f9b --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf7002dk_nrf5340_cpunet_pinctrl.dtsi @@ -0,0 +1,55 @@ +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/nordic/nrf7002dk/nrf70_common.dtsi b/boards/nordic/nrf7002dk/nrf70_common.dtsi new file mode 100644 index 000000000000..f40f8ad9bb74 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf70_common.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +iovdd-ctrl-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; +bucken-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; +host-irq-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; + +wifi-max-tx-pwr-2g-dsss = <21>; +wifi-max-tx-pwr-2g-mcs0 = <16>; +wifi-max-tx-pwr-2g-mcs7 = <16>; + +wlan0: wlan { + compatible = "nordic,wlan"; +}; diff --git a/boards/nordic/nrf7002dk/nrf70_common_5g.dtsi b/boards/nordic/nrf7002dk/nrf70_common_5g.dtsi new file mode 100644 index 000000000000..8be559cebc33 --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf70_common_5g.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +wifi-max-tx-pwr-5g-low-mcs0 = <9>; +wifi-max-tx-pwr-5g-low-mcs7 = <9>; +wifi-max-tx-pwr-5g-mid-mcs0 = <11>; +wifi-max-tx-pwr-5g-mid-mcs7 = <11>; +wifi-max-tx-pwr-5g-high-mcs0 = <13>; +wifi-max-tx-pwr-5g-high-mcs7 = <13>; diff --git a/boards/nordic/nrf7002dk/nrf70_common_coex.dtsi b/boards/nordic/nrf7002dk/nrf70_common_coex.dtsi new file mode 100644 index 000000000000..03f22c3edbaa --- /dev/null +++ b/boards/nordic/nrf7002dk/nrf70_common_coex.dtsi @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +req-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; +status0-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; +grant-gpios = <&gpio0 24 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>; +swctrl1-gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; +srrf-switch-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; diff --git a/boards/nordic/nrf7002dk/pre_dt_board.cmake b/boards/nordic/nrf7002dk/pre_dt_board.cmake new file mode 100644 index 000000000000..5db1310639dc --- /dev/null +++ b/boards/nordic/nrf7002dk/pre_dt_board.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - flash-controller@39000 & kmu@39000 +# - power@5000 & clock@5000 +# - /reserved-memory/image@20000000 & /reserved-memory/image_s@20000000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/shields/nrf7002ek/Kconfig.shield b/boards/shields/nrf7002ek/Kconfig.shield new file mode 100644 index 000000000000..7627ff96dbd4 --- /dev/null +++ b/boards/shields/nrf7002ek/Kconfig.shield @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_NRF7002EK + def_bool $(shields_list_contains,nrf7002ek) + +config SHIELD_NRF7002EK_NRF7001 + def_bool $(shields_list_contains,nrf7002ek_nrf7001) + +config SHIELD_NRF7002EK_NRF7000 + def_bool $(shields_list_contains,nrf7002ek_nrf7000) diff --git a/boards/shields/nrf7002ek/boards/nrf5340dk_nrf5340_cpuapp.overlay b/boards/shields/nrf7002ek/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 000000000000..ada3a5c61d24 --- /dev/null +++ b/boards/shields/nrf7002ek/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,15 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This node by default forwards the UART1 pins to CPUNET, but as UART1 uses + * same pins as bucken and iovdd-ctrl, we need these pins to be controlled by + * the CPUAPP. Since a child node of gpio_fwd cannot be disabled, hence + * the entire node is disabled. If the application needs to forward other pins + * to the CPUNET, it should create a separate instance of nrf-gpio-forwarder + * and use it instead. + */ +&gpio_fwd { + status = "disabled"; +}; diff --git a/boards/shields/nrf7002ek/boards/nrf9151dk_nrf9151.overlay b/boards/shields/nrf7002ek/boards/nrf9151dk_nrf9151.overlay new file mode 100644 index 000000000000..70b5f088a8f9 --- /dev/null +++ b/boards/shields/nrf7002ek/boards/nrf9151dk_nrf9151.overlay @@ -0,0 +1,6 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/boards/shields/nrf7002ek/boards/nrf9151dk_nrf9151_ns.overlay b/boards/shields/nrf7002ek/boards/nrf9151dk_nrf9151_ns.overlay new file mode 100644 index 000000000000..70b5f088a8f9 --- /dev/null +++ b/boards/shields/nrf7002ek/boards/nrf9151dk_nrf9151_ns.overlay @@ -0,0 +1,6 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/boards/shields/nrf7002ek/boards/nrf9160dk_nrf9160_ns.overlay b/boards/shields/nrf7002ek/boards/nrf9160dk_nrf9160_ns.overlay new file mode 100644 index 000000000000..410408d5ba71 --- /dev/null +++ b/boards/shields/nrf7002ek/boards/nrf9160dk_nrf9160_ns.overlay @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Disabled because of conflicts on P0.00 and P0.01 - Arduino pins D0 and D1 + * (iovdd-ctrl-gpios and bucken-gpios in nrf7002ek, respectively). + */ +&uart1 { + status = "disabled"; +}; + +/* Typically we use GPIO extender to resolve these conflicts but the + * GPIO pin used by extender itself conflicts with Wi-Fi (0.6), so, + * disable LEDs and Button0/1. + */ +&led0 { + status = "disabled"; +}; + +&led1 { + status = "disabled"; +}; + +&led2 { + status = "disabled"; +}; + +&led3 { + status = "disabled"; +}; + +&button0 { + status = "disabled"; +}; + +&button1 { + status = "disabled"; +}; diff --git a/boards/shields/nrf7002ek/boards/nrf9161dk_nrf9161.overlay b/boards/shields/nrf7002ek/boards/nrf9161dk_nrf9161.overlay new file mode 100644 index 000000000000..77cc7f915073 --- /dev/null +++ b/boards/shields/nrf7002ek/boards/nrf9161dk_nrf9161.overlay @@ -0,0 +1,6 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/boards/shields/nrf7002ek/boards/nrf9161dk_nrf9161_ns.overlay b/boards/shields/nrf7002ek/boards/nrf9161dk_nrf9161_ns.overlay new file mode 100644 index 000000000000..77cc7f915073 --- /dev/null +++ b/boards/shields/nrf7002ek/boards/nrf9161dk_nrf9161_ns.overlay @@ -0,0 +1,6 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/boards/shields/nrf7002ek/doc/index.rst b/boards/shields/nrf7002ek/doc/index.rst new file mode 100644 index 000000000000..9f247be3501d --- /dev/null +++ b/boards/shields/nrf7002ek/doc/index.rst @@ -0,0 +1,74 @@ +.. _nrf7002ek: + +nRF7002 EK +########## + +Overview +******** + +The nRF7002 EK is a versatile evaluation kit in the form of an Arduino shield that can be used in +Nordic and non-Nordic host boards. + +The nRF7002 EK unlocks low-power Wi-Fi 6 capabilities for your host device. It support dual-band Wi-Fi +2.4GHz and 5GHz, and is based on the nRF7002 SoC. +Seamlessly connect to Wi-Fi networks and leverage Wi-Fi-based locationing, enabling advanced +features such as SSID sniffing of local Wi-Fi hubs + +.. figure:: nrf7002ek.png + :alt: nRF7002 EK + :align: center + + nRF7002 EK + +Requirements +************ + +The nRF7002 EK board is designed to fit straight into an Arduino connector and uses SPI as the +communication interface. Any host board that supports the Arduino connector can be used with +the nRF7002 EK. + +Prerequisites +------------- + +the nRF70 driver requires firmware binary blobs for Wi-Fi operation. Run the command +below to retrieve those files. + +.. code-block:: console + + west update + west blobs fetch hal_nordic + +Usage +***** + +The shield can be used in any application by setting ``--shield nrf7002ek`` when invoking ``west build``. + +SR Co-existence +############### + +The nRF7002 EK supports SR co-existence provided the host board supports it. The SR co-existence +pins are connected to the host board's GPIO pins. + +Two Kconfig options are available to enable SR co-existence: + +- :kconfig:option:`CONFIG_NRF70_SR_COEX`: Enables SR co-existence. +- :kconfig:option:`CONFIG_NRF70_SR_COEX_RF_SWITCH`: Control SR side RF switch. + +Shield Variants +############### + +The nRF7002 EK is available in three variants: + +- ``nrf7002ek``: The default variant. +- ``nrf7002ek_nrf7001``: Variant for the nRF7001 SoC or nRF7002 SoC emulating nRF7001 + that supports only 2.4GHz Wi-Fi. +- ``nrf7002ek_nrf7000``: Variant for the nRF7000 SoC or nRF7002 SoC emulating nRF7000 + that supports only 2.4GHz Wi-Fi. + + +References +********** + +- `nRF7002 EK product page `_ +- `nRF7002 product specification `_ +- `nRF7002 EK Co-existence `_ diff --git a/boards/shields/nrf7002ek/doc/nrf7002ek.png b/boards/shields/nrf7002ek/doc/nrf7002ek.png new file mode 100644 index 000000000000..9b4b09753719 Binary files /dev/null and b/boards/shields/nrf7002ek/doc/nrf7002ek.png differ diff --git a/boards/shields/nrf7002ek/nrf7002ek.overlay b/boards/shields/nrf7002ek/nrf7002ek.overlay new file mode 100644 index 000000000000..2a0f09bd955e --- /dev/null +++ b/boards/shields/nrf7002ek/nrf7002ek.overlay @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + chosen { + zephyr,wifi = &wlan0; + }; +}; + +&arduino_spi { + status = "okay"; + + nrf70: nrf7002-spi@0 { + compatible = "nordic,nrf7002-spi"; + status = "okay"; + reg = <0>; + spi-max-frequency = ; + + /* Include common nRF70 overlays */ + #include "nrf7002ek_common.dtsi" + #include "nrf7002ek_common_5g.dtsi" + }; +}; diff --git a/boards/shields/nrf7002ek/nrf7002ek_common.dtsi b/boards/shields/nrf7002ek/nrf7002ek_common.dtsi new file mode 100644 index 000000000000..102e0078d5f3 --- /dev/null +++ b/boards/shields/nrf7002ek/nrf7002ek_common.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Common assignments for any nRF70 shield */ + +/* D0 */ +iovdd-ctrl-gpios = <&arduino_header 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; +/* D1 */ +bucken-gpios = <&arduino_header 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; +/* D7 */ +host-irq-gpios = <&arduino_header 13 GPIO_ACTIVE_HIGH>; +/* Short-range (SR) co-existence */ +/* D2 */ +status0-gpios = <&arduino_header 8 GPIO_ACTIVE_HIGH>; +/* D3 */ +req-gpios = <&arduino_header 9 GPIO_ACTIVE_HIGH>; +/* D4 */ +grant-gpios = <&arduino_header 10 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>; +/* D6 */ +swctrl1-gpios = <&arduino_header 12 GPIO_ACTIVE_HIGH>; +/* D8 */ +srrf-switch-gpios = <&arduino_header 14 GPIO_ACTIVE_HIGH>; + +/* Maximum TX power limits for 2.4 GHz */ +wifi-max-tx-pwr-2g-dsss = <21>; +wifi-max-tx-pwr-2g-mcs0 = <16>; +wifi-max-tx-pwr-2g-mcs7 = <16>; + +/* List of interfaces */ +wlan0: wlan0 { + compatible = "nordic,wlan"; +}; diff --git a/boards/shields/nrf7002ek/nrf7002ek_common_5g.dtsi b/boards/shields/nrf7002ek/nrf7002ek_common_5g.dtsi new file mode 100644 index 000000000000..8faa9b945feb --- /dev/null +++ b/boards/shields/nrf7002ek/nrf7002ek_common_5g.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +wifi-max-tx-pwr-5g-low-mcs0 = <13>; +wifi-max-tx-pwr-5g-low-mcs7 = <13>; +wifi-max-tx-pwr-5g-mid-mcs0 = <13>; +wifi-max-tx-pwr-5g-mid-mcs7 = <13>; +wifi-max-tx-pwr-5g-high-mcs0 = <12>; +wifi-max-tx-pwr-5g-high-mcs7 = <12>; diff --git a/boards/shields/nrf7002ek/nrf7002ek_nrf7000.overlay b/boards/shields/nrf7002ek/nrf7002ek_nrf7000.overlay new file mode 100644 index 000000000000..28a3662f1d67 --- /dev/null +++ b/boards/shields/nrf7002ek/nrf7002ek_nrf7000.overlay @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + chosen { + zephyr,wifi = &wlan0; + }; +}; + +&arduino_spi { + status = "okay"; + + nrf70: nrf7002-spi@0 { + compatible = "nordic,nrf7000-spi"; + status = "okay"; + reg = <0>; + spi-max-frequency = ; + + /* Include common nRF70 overlays */ + #include "nrf7002ek_common.dtsi" + #include "nrf7002ek_common_5g.dtsi" + }; +}; diff --git a/boards/shields/nrf7002ek/nrf7002ek_nrf7001.overlay b/boards/shields/nrf7002ek/nrf7002ek_nrf7001.overlay new file mode 100644 index 000000000000..a3b84d1761d5 --- /dev/null +++ b/boards/shields/nrf7002ek/nrf7002ek_nrf7001.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + chosen { + zephyr,wifi = &wlan0; + }; +}; + +&arduino_spi { + status = "okay"; + + nrf70: nrf7001-spi@0 { + compatible = "nordic,nrf7001-spi"; + status = "okay"; + reg = <0>; + spi-max-frequency = ; + + /* Include common nRF70 overlays */ + #include "nrf7002ek_common.dtsi" + }; +}; diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index d2b36017051b..ef1cc20e67a4 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -386,6 +386,10 @@ static int uarte_nrfx_configure(const struct device *dev, struct uarte_nrfx_data *data = dev->data; nrf_uarte_config_t uarte_cfg; +#if NRF_UARTE_HAS_FRAME_TIMEOUT + uarte_cfg.frame_timeout = NRF_UARTE_FRAME_TIMEOUT_DIS; +#endif + #if defined(UARTE_CONFIG_STOP_Msk) switch (cfg->stop_bits) { case UART_CFG_STOP_BITS_1: diff --git a/drivers/serial/uart_nrfx_uarte2.c b/drivers/serial/uart_nrfx_uarte2.c index 99c70f47831d..e00fe7a6d0a3 100644 --- a/drivers/serial/uart_nrfx_uarte2.c +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -643,6 +643,10 @@ static int uarte_nrfx_configure(const struct device *dev, struct uarte_nrfx_data *data = dev->data; nrf_uarte_config_t uarte_cfg; +#if NRF_UARTE_HAS_FRAME_TIMEOUT + uarte_cfg.frame_timeout = NRF_UARTE_FRAME_TIMEOUT_DIS; +#endif + #if defined(UARTE_CONFIG_STOP_Msk) switch (cfg->stop_bits) { case UART_CFG_STOP_BITS_1: diff --git a/drivers/wifi/CMakeLists.txt b/drivers/wifi/CMakeLists.txt index df1e7c394653..78a91d480cfd 100644 --- a/drivers/wifi/CMakeLists.txt +++ b/drivers/wifi/CMakeLists.txt @@ -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) diff --git a/drivers/wifi/Kconfig b/drivers/wifi/Kconfig index d7133f5be040..769a23b4eb64 100644 --- a/drivers/wifi/Kconfig +++ b/drivers/wifi/Kconfig @@ -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 diff --git a/drivers/wifi/nrfwifi/CMakeLists.txt b/drivers/wifi/nrfwifi/CMakeLists.txt new file mode 100644 index 000000000000..3d1ea0ba37b7 --- /dev/null +++ b/drivers/wifi/nrfwifi/CMakeLists.txt @@ -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_COMMON + src/wifi_mgmt.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_ifdef(CONFIG_NRF70_AP_MODE + -DNRF70_AP_MODE +) + +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} +) diff --git a/drivers/wifi/nrfwifi/Kconfig.nrfwifi b/drivers/wifi/nrfwifi/Kconfig.nrfwifi new file mode 100644 index 000000000000..592954bf28e9 --- /dev/null +++ b/drivers/wifi/nrfwifi/Kconfig.nrfwifi @@ -0,0 +1,730 @@ +# 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 NRF70_SYSTEM_MODE_COMMON + bool + default y if NRF70_SYSTEM_MODE || NRF70_SYSTEM_WITH_RAW_MODES + +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. + +config NRF_WIFI_FEAT_WMM + bool "WMM/QoS support" + default y + help + This option controls disable/enable of the WMM(Wireless Multi-Media) feature. + +# TODO: Temporary WAR, implement these options in the future +config NRF_WIFI_PATCHES_EXT_FLASH_DISABLED + bool "nRF70 firmware patch external flash support" + help + Select this option to disable external flash support for nRF70 firmware patches + +config NRF_WIFI_FW_PATCH_DFU + bool "nRF70 firmware patch DFU" + help + Select this option to enable DFU for nRF70 firmware patches + +config NRF_WIFI_PATCHES_EXT_FLASH_STORE + bool "nRF70 firmware patch external flash store" + help + Select this option to enable external flash store for nRF70 firmware patches + +config NRF_WIFI_FW_FLASH_CHUNK_SIZE + int "nRF70 firmware patch flash chunk size" + default 8192 + help + Select this option to set the flash chunk size for nRF70 firmware patches + +config NRF_WIFI_PATCHES_EXT_FLASH_XIP + bool "nRF70 firmware patch external flash XIP" + help + Select this option to enable external flash XIP for nRF70 firmware patches + +choice NRF_WIFI_PS_DATA_RETRIEVAL_MECHANISM + prompt "Power save data retrieval mechanism" + default NRF_WIFI_PS_POLL_BASED_RETRIEVAL + help + Select the mechanism to retrieve buffered data from AP. + +config NRF_WIFI_PS_POLL_BASED_RETRIEVAL + bool "PS-Poll frame based mechanism to retrieve buffered data from AP" + help + When AP notifies about availability of buffered data, the STA stays in power save + and retrieves the frames one-by-one, this conserved more power but adds latency + to the traffic. Ideal for minimum number of frames. + +config NRF_WIFI_QOS_NULL_BASED_RETRIEVAL + bool "QoS null frame based mechanism to retrieve buffered data from AP" + help + When AP notifies about availability of buffered data, the STA comes out of + power save and then AP can deliver all buffered frames without any additional + overhead or latency, but STA enters power save after a delay costing more power + depending on the delay. Ideal for heavy buffered traffic. + +endchoice + +endif # WIFI_NRF70 diff --git a/drivers/wifi/nrfwifi/inc/coex.h b/drivers/wifi/nrfwifi/inc/coex.h new file mode 100644 index 000000000000..969a4c9628dc --- /dev/null +++ b/drivers/wifi/nrfwifi/inc/coex.h @@ -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 + +/* 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__ */ diff --git a/drivers/wifi/nrfwifi/inc/coex_struct.h b/drivers/wifi/nrfwifi/inc/coex_struct.h new file mode 100644 index 000000000000..a6695b47fbc7 --- /dev/null +++ b/drivers/wifi/nrfwifi/inc/coex_struct.h @@ -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 +#include + +/* 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__ */ diff --git a/drivers/wifi/nrfwifi/inc/fmac_main.h b/drivers/wifi/nrfwifi/inc/fmac_main.h new file mode 100644 index 000000000000..f5de235a0f51 --- /dev/null +++ b/drivers/wifi/nrfwifi/inc/fmac_main.h @@ -0,0 +1,134 @@ +/* + * 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 + +#include + +#include +#include +#ifndef CONFIG_NRF70_RADIO_TEST +#include +#include +#ifdef CONFIG_NETWORKING +#include +#endif /* CONFIG_NETWORKING */ +#ifdef CONFIG_NRF70_STA_MODE +#include +#endif /* CONFIG_NRF70_STA_MODE */ +#endif /* !CONFIG_NRF70_RADIO_TEST */ + +#include +#include + +#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__ */ diff --git a/drivers/wifi/nrfwifi/inc/net_if.h b/drivers/wifi/nrfwifi/inc/net_if.h new file mode 100644 index 000000000000..8d97802ba65c --- /dev/null +++ b/drivers/wifi/nrfwifi/inc/net_if.h @@ -0,0 +1,66 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#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); + +int nrf_wifi_stats_reset(const struct device *dev); +#endif /* __ZEPHYR_NET_IF_H__ */ diff --git a/drivers/wifi/nrfwifi/inc/wifi_mgmt.h b/drivers/wifi/nrfwifi/inc/wifi_mgmt.h new file mode 100644 index 000000000000..2e169bc0dcad --- /dev/null +++ b/drivers/wifi/nrfwifi/inc/wifi_mgmt.h @@ -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 + +#include +#include + +#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__ */ diff --git a/drivers/wifi/nrfwifi/inc/wifi_mgmt_scan.h b/drivers/wifi/nrfwifi/inc/wifi_mgmt_scan.h new file mode 100644 index 000000000000..e97f9293a34b --- /dev/null +++ b/drivers/wifi/nrfwifi/inc/wifi_mgmt_scan.h @@ -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 +#include + +#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__ */ diff --git a/drivers/wifi/nrfwifi/inc/wpa_supp_if.h b/drivers/wifi/nrfwifi/inc/wpa_supp_if.h new file mode 100644 index 000000000000..06a13261a706 --- /dev/null +++ b/drivers/wifi/nrfwifi/inc/wpa_supp_if.h @@ -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 + +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__ */ diff --git a/drivers/wifi/nrfwifi/rpu_fw_patches.ld b/drivers/wifi/nrfwifi/rpu_fw_patches.ld new file mode 100644 index 000000000000..4ecbaedb0960 --- /dev/null +++ b/drivers/wifi/nrfwifi/rpu_fw_patches.ld @@ -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 +#include + +#include +#include + +#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 +#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 diff --git a/drivers/wifi/nrfwifi/src/coex.c b/drivers/wifi/nrfwifi/src/coex.c new file mode 100644 index 000000000000..7bb89a07e9ed --- /dev/null +++ b/drivers/wifi/nrfwifi/src/coex.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Coexistence functions + */ + +#include +#include +#include +#include +#include + +#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 *)(¶ms), 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 *)(¶ms), 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 *)(¶ms), 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 */ diff --git a/drivers/wifi/nrfwifi/src/fmac_main.c b/drivers/wifi/nrfwifi/src/fmac_main.c new file mode 100644 index 000000000000..99b6c8cdf72d --- /dev/null +++ b/drivers/wifi/nrfwifi/src/fmac_main.c @@ -0,0 +1,945 @@ +/* + * 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 + +#include +#ifdef CONFIG_NET_L2_ETHERNET +#include +#endif +#include +#include +#include +#include + + +#include +#include +#include "fmac_util.h" +#include + +#ifndef CONFIG_NRF70_RADIO_TEST +#ifdef CONFIG_NRF70_STA_MODE +#include +#include +#include +#include +#else +#include +#include +#endif /* CONFIG_NRF70_STA_MODE */ +#include + +#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; +extern const struct nrf_wifi_osal_ops nrf_wifi_os_zep_ops; + +/* 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 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(); +} +#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(®_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, ®_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, ®_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(®_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 = IS_ENABLED(CONFIG_NRF_WIFI_FEAT_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 */ + + /* The OSAL layer needs to be initialized before any other initialization + * so that other layers (like FW IF,HW IF etc) have access to OS ops + */ + nrf_wifi_osal_init(&nrf_wifi_os_zep_ops); + + 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; + + /* The OSAL layer needs to be initialized before any other initialization + * so that other layers (like FW IF,HW IF etc) have access to OS ops + */ + nrf_wifi_osal_init(&nrf_wifi_os_zep_ops); + + 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); + nrf_wifi_osal_deinit(); +#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, + .reset_stats = nrf_wifi_stats_reset, +#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 */ diff --git a/drivers/wifi/nrfwifi/src/fw_load.c b/drivers/wifi/nrfwifi/src/fw_load.c new file mode 100644 index 000000000000..14087a7d35ca --- /dev/null +++ b/drivers/wifi/nrfwifi/src/fw_load.c @@ -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 +#include + +#include +#include + +#include +LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL); + +#include + +#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; +} diff --git a/drivers/wifi/nrfwifi/src/net_if.c b/drivers/wifi/nrfwifi/src/net_if.c new file mode 100644 index 000000000000..94d53e2a2761 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/net_if.c @@ -0,0 +1,1203 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief File containing netowrk stack interface specific definitions for the + * Zephyr OS layer of the Wi-Fi driver. + */ + +#include + +#ifdef CONFIG_WIFI_RANDOM_MAC_ADDRESS +#include +#endif + +#include +LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL); + +#include "net_private.h" + +#include "util.h" +#include "fmac_api.h" +#include "fmac_util.h" +#include "shim.h" +#include "fmac_main.h" +#include "wpa_supp_if.h" +#include "net_if.h" + +extern char *net_sprint_ll_addr_buf(const uint8_t *ll, uint8_t ll_len, + char *buf, int buflen); + +#ifdef CONFIG_NRF70_STA_MODE +static struct net_if_mcast_monitor mcast_monitor; +#endif /* CONFIG_NRF70_STA_MODE */ + +void nrf_wifi_set_iface_event_handler(void *os_vif_ctx, + struct nrf_wifi_umac_event_set_interface *event, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!os_vif_ctx) { + LOG_ERR("%s: Invalid parameters", + __func__); + goto out; + } + + if (!event) { + LOG_ERR("%s: event is NULL", + __func__); + goto out; + } + + (void)event_len; + + vif_ctx_zep = os_vif_ctx; + + vif_ctx_zep->set_if_event_received = true; + vif_ctx_zep->set_if_status = event->return_value; + +out: + return; +} + +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY +static void nrf_wifi_rpu_recovery_work_handler(struct k_work *work) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = CONTAINER_OF(work, + struct nrf_wifi_vif_ctx_zep, + nrf_wifi_rpu_recovery_work); + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + return; + } + + if (!vif_ctx_zep->zep_net_if_ctx) { + LOG_ERR("%s: zep_net_if_ctx is NULL", __func__); + return; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return; + } + + k_mutex_lock(&rpu_ctx_zep->rpu_lock, K_FOREVER); + LOG_DBG("%s: Bringing the interface down", __func__); + /* This indirectly does a cold-boot of RPU */ + net_if_down(vif_ctx_zep->zep_net_if_ctx); + k_msleep(CONFIG_NRF_WIFI_RPU_RECOVERY_PROPAGATION_DELAY_MS); + LOG_DBG("%s: Bringing the interface up", __func__); + net_if_up(vif_ctx_zep->zep_net_if_ctx); + k_mutex_unlock(&rpu_ctx_zep->rpu_lock); +} + +void nrf_wifi_rpu_recovery_cb(void *vif_ctx_handle, + void *event_data, + unsigned int event_len) +{ + struct nrf_wifi_fmac_vif_ctx *vif_ctx = vif_ctx_handle; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!vif_ctx) { + LOG_ERR("%s: vif_ctx is NULL", + __func__); + goto out; + } + + fmac_dev_ctx = vif_ctx->fmac_dev_ctx; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + if (!def_dev_ctx) { + LOG_ERR("%s: def_dev_ctx is NULL", + __func__); + goto out; + } + + vif_ctx_zep = vif_ctx->os_vif_ctx; + (void)event_data; + + k_work_submit(&vif_ctx_zep->nrf_wifi_rpu_recovery_work); +out: + return; +} +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ + +#ifdef CONFIG_NRF70_DATA_TX +static void nrf_wifi_net_iface_work_handler(struct k_work *work) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = CONTAINER_OF(work, + struct nrf_wifi_vif_ctx_zep, + nrf_wifi_net_iface_work); + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + return; + } + + if (!vif_ctx_zep->zep_net_if_ctx) { + LOG_ERR("%s: zep_net_if_ctx is NULL", __func__); + return; + } + + if (vif_ctx_zep->if_carr_state == NRF_WIFI_FMAC_IF_CARR_STATE_ON) { + net_if_dormant_off(vif_ctx_zep->zep_net_if_ctx); + } else if (vif_ctx_zep->if_carr_state == NRF_WIFI_FMAC_IF_CARR_STATE_OFF) { + net_if_dormant_on(vif_ctx_zep->zep_net_if_ctx); + } +} + +#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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = os_vif_ctx; + struct net_if *iface = vif_ctx_zep->zep_net_if_ctx; + struct net_pkt *pkt; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = rpu_ctx_zep->rpu_ctx; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + int ret; + + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + + pkt = net_raw_pkt_from_nbuf(iface, frm, sizeof(struct raw_rx_pkt_header), + raw_rx_hdr, + pkt_free); + if (!pkt) { + LOG_DBG("Failed to allocate net_pkt"); + return; + } + + net_capture_pkt(iface, pkt); + + ret = net_recv_data(iface, pkt); + if (ret < 0) { + LOG_DBG("RCV Packet dropped by NET stack: %d", ret); + net_pkt_unref(pkt); + } +} +#endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */ + +void nrf_wifi_if_rx_frm(void *os_vif_ctx, void *frm) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = os_vif_ctx; + struct net_if *iface = vif_ctx_zep->zep_net_if_ctx; + struct net_pkt *pkt; + int status; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = rpu_ctx_zep->rpu_ctx; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + struct rpu_host_stats *host_stats = NULL; + + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + host_stats = &def_dev_ctx->host_stats; + host_stats->total_rx_pkts++; + + pkt = net_pkt_from_nbuf(iface, frm); + if (!pkt) { + LOG_DBG("Failed to allocate net_pkt"); + host_stats->total_rx_drop_pkts++; + return; + } + + status = net_recv_data(iface, pkt); + + if (status < 0) { + LOG_DBG("RCV Packet dropped by NET stack: %d", status); + host_stats->total_rx_drop_pkts++; + net_pkt_unref(pkt); + } +} + +enum nrf_wifi_status nrf_wifi_if_carr_state_chg(void *os_vif_ctx, + enum nrf_wifi_fmac_if_carr_state carr_state) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!os_vif_ctx) { + LOG_ERR("%s: Invalid parameters", + __func__); + goto out; + } + + vif_ctx_zep = os_vif_ctx; + + vif_ctx_zep->if_carr_state = carr_state; + + LOG_DBG("%s: Carrier state: %d", __func__, carr_state); + + k_work_submit(&vif_ctx_zep->nrf_wifi_net_iface_work); + + status = NRF_WIFI_STATUS_SUCCESS; + +out: + return status; +} + +static bool is_eapol(struct net_pkt *pkt) +{ + struct net_eth_hdr *hdr; + uint16_t ethertype; + + hdr = NET_ETH_HDR(pkt); + ethertype = ntohs(hdr->type); + + return ethertype == NET_ETH_PTYPE_EAPOL; +} +#endif /* CONFIG_NRF70_DATA_TX */ + +enum ethernet_hw_caps nrf_wifi_if_caps_get(const struct device *dev) +{ + enum ethernet_hw_caps caps = (ETHERNET_LINK_10BASE_T | + ETHERNET_LINK_100BASE_T | ETHERNET_LINK_1000BASE_T); + +#ifdef CONFIG_NRF70_TCP_IP_CHECKSUM_OFFLOAD + caps |= ETHERNET_HW_TX_CHKSUM_OFFLOAD | + ETHERNET_HW_RX_CHKSUM_OFFLOAD; +#endif /* CONFIG_NRF70_TCP_IP_CHECKSUM_OFFLOAD */ + +#ifdef CONFIG_NRF70_RAW_DATA_TX + caps |= ETHERNET_TXINJECTION_MODE; +#endif +#ifdef CONFIG_NRF70_PROMISC_DATA_RX + caps |= ETHERNET_PROMISC_MODE; +#endif + return caps; +} + +int nrf_wifi_if_send(const struct device *dev, + struct net_pkt *pkt) +{ + int ret = -1; +#ifdef CONFIG_NRF70_DATA_TX + 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_def *def_dev_ctx = NULL; + struct rpu_host_stats *host_stats = NULL; + void *nbuf = NULL; + + if (!dev || !pkt) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + goto out; + } + + vif_ctx_zep = dev->data; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + goto unlock; + } + + def_dev_ctx = wifi_dev_priv(rpu_ctx_zep->rpu_ctx); + host_stats = &def_dev_ctx->host_stats; + nbuf = net_pkt_to_nbuf(pkt); + if (!nbuf) { + LOG_DBG("Failed to allocate net_pkt"); + host_stats->total_tx_drop_pkts++; + goto out; + } + +#ifdef CONFIG_NRF70_RAW_DATA_TX + if ((*(unsigned int *)pkt->frags->data) == NRF_WIFI_MAGIC_NUM_RAWTX) { + if (vif_ctx_zep->if_carr_state != NRF_WIFI_FMAC_IF_CARR_STATE_ON) { + goto unlock; + } + + ret = nrf_wifi_fmac_start_rawpkt_xmit(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + nbuf); + } else { +#endif /* CONFIG_NRF70_RAW_DATA_TX */ + if ((vif_ctx_zep->if_carr_state != NRF_WIFI_FMAC_IF_CARR_STATE_ON) || + (!vif_ctx_zep->authorized && !is_eapol(pkt))) { + goto unlock; + } + + ret = nrf_wifi_fmac_start_xmit(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + nbuf); +#ifdef CONFIG_NRF70_RAW_DATA_TX + } +#endif /* CONFIG_NRF70_RAW_DATA_TX */ +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +#else + ARG_UNUSED(dev); + ARG_UNUSED(pkt); + goto out; +#endif /* CONFIG_NRF70_DATA_TX */ + +out: + return ret; +} + +#ifdef CONFIG_NRF70_STA_MODE +static void ip_maddr_event_handler(struct net_if *iface, + const struct net_addr *addr, bool is_joined) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct net_eth_addr mac_addr; + struct nrf_wifi_umac_mcast_cfg *mcast_info = NULL; + enum nrf_wifi_status status; + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret; + + vif_ctx_zep = nrf_wifi_get_vif_ctx(iface); + if (!vif_ctx_zep) { + return; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: rpu_ctx_zep or rpu_ctx is NULL", + __func__); + goto unlock; + } + + mcast_info = k_calloc(sizeof(*mcast_info), sizeof(char)); + + if (!mcast_info) { + LOG_ERR("%s: Unable to allocate memory of size %d " + "for mcast_info", __func__, sizeof(*mcast_info)); + return; + } + + switch (addr->family) { + case AF_INET: + net_eth_ipv4_mcast_to_mac_addr(&addr->in_addr, &mac_addr); + break; + case AF_INET6: + net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr); + break; + default: + LOG_ERR("%s: Invalid address family %d", __func__, addr->family); + break; + } + + if (is_joined) { + mcast_info->type = MCAST_ADDR_ADD; + } else { + mcast_info->type = MCAST_ADDR_DEL; + } + + memcpy(((char *)(mcast_info->mac_addr)), + &mac_addr, + NRF_WIFI_ETH_ADDR_LEN); + + status = nrf_wifi_fmac_set_mcast_addr(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + mcast_info); + if (status == NRF_WIFI_STATUS_FAIL) { + LOG_ERR("%s: nrf_wifi_fmac_set_multicast failed for" + " mac addr=%s", + __func__, + net_sprint_ll_addr_buf(mac_addr.addr, + WIFI_MAC_ADDR_LEN, mac_string_buf, + sizeof(mac_string_buf))); + } +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +out: + k_free(mcast_info); +} +#endif /* CONFIG_NRF70_STA_MODE */ + +#ifdef CONFIG_WIFI_FIXED_MAC_ADDRESS_ENABLED +BUILD_ASSERT(sizeof(CONFIG_WIFI_FIXED_MAC_ADDRESS) - 1 == ((WIFI_MAC_ADDR_LEN * 2) + 5), + "Invalid fixed MAC address length"); +#endif + +enum nrf_wifi_status nrf_wifi_get_mac_addr(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", + __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: rpu_ctx_zep or rpu_ctx is NULL", + __func__); + goto unlock; + } + + fmac_dev_ctx = rpu_ctx_zep->rpu_ctx; + +#ifdef CONFIG_WIFI_FIXED_MAC_ADDRESS_ENABLED + char fixed_mac_addr[WIFI_MAC_ADDR_LEN]; + + ret = net_bytes_from_str(fixed_mac_addr, + WIFI_MAC_ADDR_LEN, + CONFIG_WIFI_FIXED_MAC_ADDRESS); + if (ret < 0) { + LOG_ERR("%s: Failed to parse MAC address: %s", + __func__, + CONFIG_WIFI_FIXED_MAC_ADDRESS); + goto unlock; + } + + memcpy(vif_ctx_zep->mac_addr.addr, + fixed_mac_addr, + WIFI_MAC_ADDR_LEN); +#elif CONFIG_WIFI_RANDOM_MAC_ADDRESS + char random_mac_addr[WIFI_MAC_ADDR_LEN]; + + sys_rand_get(random_mac_addr, WIFI_MAC_ADDR_LEN); + random_mac_addr[0] = (random_mac_addr[0] & UNICAST_MASK) | LOCAL_BIT; + + memcpy(vif_ctx_zep->mac_addr.addr, + random_mac_addr, + WIFI_MAC_ADDR_LEN); +#elif CONFIG_WIFI_OTP_MAC_ADDRESS + status = nrf_wifi_fmac_otp_mac_addr_get(fmac_dev_ctx, + vif_ctx_zep->vif_idx, + vif_ctx_zep->mac_addr.addr); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Fetching of MAC address from OTP failed", + __func__); + goto unlock; + } +#endif + + if (!nrf_wifi_utils_is_mac_addr_valid(vif_ctx_zep->mac_addr.addr)) { + LOG_ERR("%s: Invalid MAC address: %s", + __func__, + net_sprint_ll_addr(vif_ctx_zep->mac_addr.addr, + WIFI_MAC_ADDR_LEN)); + status = NRF_WIFI_STATUS_FAIL; + memset(vif_ctx_zep->mac_addr.addr, + 0, + WIFI_MAC_ADDR_LEN); + goto unlock; + } + status = NRF_WIFI_STATUS_SUCCESS; +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +out: + return status; +} + +void nrf_wifi_if_init_zep(struct net_if *iface) +{ + const struct device *dev = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + + if (!iface) { + LOG_ERR("%s: Invalid parameters", + __func__); + return; + } + + dev = net_if_get_device(iface); + + if (!dev) { + LOG_ERR("%s: Invalid dev", + __func__); + return; + } + + vif_ctx_zep = dev->data; + + 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; + } + + vif_ctx_zep->zep_net_if_ctx = iface; + vif_ctx_zep->zep_dev_ctx = dev; + + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; + ethernet_init(iface); + net_eth_carrier_on(iface); + net_if_dormant_on(iface); + +#ifdef CONFIG_NRF70_STA_MODE + net_if_mcast_mon_register(&mcast_monitor, iface, ip_maddr_event_handler); +#endif /* CONFIG_NRF70_STA_MODE */ +#ifdef CONFIG_NRF70_DATA_TX + k_work_init(&vif_ctx_zep->nrf_wifi_net_iface_work, + nrf_wifi_net_iface_work_handler); +#endif /* CONFIG_NRF70_DATA_TX */ + +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + k_work_init(&vif_ctx_zep->nrf_wifi_rpu_recovery_work, + nrf_wifi_rpu_recovery_work_handler); +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ + +#if !defined(CONFIG_NRF_WIFI_IF_AUTO_START) + net_if_flag_set(iface, NET_IF_NO_AUTO_START); +#endif /* CONFIG_NRF_WIFI_IF_AUTO_START */ + net_if_flag_set(iface, NET_IF_NO_TX_LOCK); +} + +/* Board-specific Wi-Fi startup code to run before the Wi-Fi device is started */ +__weak int nrf_wifi_if_zep_start_board(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} + +/* Board-specific Wi-Fi shutdown code to run after the Wi-Fi device is stopped */ +__weak int nrf_wifi_if_zep_stop_board(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} + +int nrf_wifi_if_start_zep(const struct device *dev) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + 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; + struct nrf_wifi_umac_chg_vif_state_info vif_info; + struct nrf_wifi_umac_add_vif_info add_vif_info; + char *mac_addr = NULL; + unsigned int mac_addr_len = 0; + int ret = -1; + bool fmac_dev_added = false; + + if (!dev) { + LOG_ERR("%s: Invalid parameters", + __func__); + goto out; + } + + if (!device_is_ready(dev)) { + LOG_ERR("%s: Device %s is not ready", + __func__, dev->name); + goto out; + } + + ret = nrf_wifi_if_zep_start_board(dev); + if (ret) { + LOG_ERR("nrf_wifi_if_zep_start_board failed with error: %d", + ret); + goto out; + } + + vif_ctx_zep = dev->data; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", + __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", + __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + if (!rpu_ctx_zep->rpu_ctx) { + 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 out; + } + fmac_dev_added = true; + LOG_DBG("%s: FMAC device added", __func__); + } + + fmac_dev_ctx = rpu_ctx_zep->rpu_ctx; + + memset(&add_vif_info, + 0, + sizeof(add_vif_info)); + + /* TODO: This should be configurable */ + add_vif_info.iftype = NRF_WIFI_IFTYPE_STATION; + + memcpy(add_vif_info.ifacename, + dev->name, + strlen(dev->name)); + + vif_ctx_zep->vif_idx = nrf_wifi_fmac_add_vif(fmac_dev_ctx, + vif_ctx_zep, + &add_vif_info); + if (vif_ctx_zep->vif_idx >= MAX_NUM_VIFS) { + LOG_ERR("%s: FMAC returned invalid interface index", + __func__); + goto dev_rem; + } + + k_mutex_init(&vif_ctx_zep->vif_lock); + rpu_ctx_zep->vif_ctx_zep[vif_ctx_zep->vif_idx].if_type = + add_vif_info.iftype; + + /* Check if user has provided a valid MAC address, if not + * fetch it from OTP. + */ + mac_addr = net_if_get_link_addr(vif_ctx_zep->zep_net_if_ctx)->addr; + mac_addr_len = net_if_get_link_addr(vif_ctx_zep->zep_net_if_ctx)->len; + + if (!nrf_wifi_utils_is_mac_addr_valid(mac_addr)) { + status = nrf_wifi_get_mac_addr(vif_ctx_zep); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Failed to get MAC address", + __func__); + goto del_vif; + } + net_if_set_link_addr(vif_ctx_zep->zep_net_if_ctx, + vif_ctx_zep->mac_addr.addr, + WIFI_MAC_ADDR_LEN, + NET_LINK_ETHERNET); + mac_addr = vif_ctx_zep->mac_addr.addr; + mac_addr_len = WIFI_MAC_ADDR_LEN; + } + + status = nrf_wifi_fmac_set_vif_macaddr(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + mac_addr); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: MAC address change failed", + __func__); + goto del_vif; + } + + memset(&vif_info, + 0, + sizeof(vif_info)); + + vif_info.state = NRF_WIFI_FMAC_IF_OP_STATE_UP; + vif_info.if_index = vif_ctx_zep->vif_idx; + + memcpy(vif_ctx_zep->ifname, + dev->name, + strlen(dev->name)); + + status = nrf_wifi_fmac_chg_vif_state(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &vif_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_chg_vif_state failed", + __func__); + goto del_vif; + } + +#ifdef CONFIG_NRF70_STA_MODE + nrf_wifi_wpa_supp_event_mac_chgd(vif_ctx_zep); + +#ifdef CONFIG_NRF_WIFI_LOW_POWER + status = nrf_wifi_fmac_set_power_save(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + NRF_WIFI_PS_ENABLED); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_set_power_save failed", + __func__); + goto dev_rem; + } +#endif /* CONFIG_NRF_WIFI_LOW_POWER */ +#endif /* CONFIG_NRF70_STA_MODE */ + + vif_ctx_zep->if_op_state = NRF_WIFI_FMAC_IF_OP_STATE_UP; + + ret = 0; + + goto out; +del_vif: + status = nrf_wifi_fmac_del_vif(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_del_vif failed", + __func__); + } +dev_rem: + /* Free only if we added above i.e., for 1st VIF */ + if (fmac_dev_added) { + nrf_wifi_fmac_dev_rem_zep(&rpu_drv_priv_zep); + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + + +int nrf_wifi_if_stop_zep(const struct device *dev) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_chg_vif_state_info vif_info; + int ret = -1; + + if (!dev) { + LOG_ERR("%s: Invalid parameters", + __func__); + goto out; + } + + vif_ctx_zep = dev->data; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", + __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", + __func__); + goto out; + } + +#ifdef CONFIG_NRF70_STA_MODE +#ifdef CONFIG_NRF_WIFI_LOW_POWER + status = nrf_wifi_fmac_set_power_save(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + NRF_WIFI_PS_DISABLED); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_set_power_save failed", + __func__); + goto unlock; + } +#endif /* CONFIG_NRF_WIFI_LOW_POWER */ +#endif /* CONFIG_NRF70_STA_MODE */ + + memset(&vif_info, + 0, + sizeof(vif_info)); + + vif_info.state = NRF_WIFI_FMAC_IF_OP_STATE_DOWN; + vif_info.if_index = vif_ctx_zep->vif_idx; + + status = nrf_wifi_fmac_chg_vif_state(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &vif_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_chg_vif_state failed", + __func__); + goto unlock; + } + + status = nrf_wifi_fmac_del_vif(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_del_vif failed", + __func__); + goto unlock; + } + + vif_ctx_zep->if_op_state = NRF_WIFI_FMAC_IF_OP_STATE_DOWN; + + if (nrf_wifi_fmac_get_num_vifs(rpu_ctx_zep->rpu_ctx) == 0) { + nrf_wifi_fmac_dev_rem_zep(&rpu_drv_priv_zep); + } + ret = 0; +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + + ret = nrf_wifi_if_zep_stop_board(dev); + if (ret) { + LOG_ERR("nrf_wifi_if_zep_stop_board failed with error: %d", + ret); + } +out: + return ret; +} + +int nrf_wifi_if_get_config_zep(const struct device *dev, + enum ethernet_config_type type, + struct ethernet_config *config) +{ + int ret = -1; +#ifdef CONFIG_NRF70_RAW_DATA_TX + 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; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + + if (!dev || !config) { + LOG_ERR("%s: Invalid parameters", + __func__); + goto out; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", + __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: rpu_ctx_zep or rpu_ctx is NULL", + __func__); + goto unlock; + } + fmac_dev_ctx = rpu_ctx_zep->rpu_ctx; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + if (!def_dev_ctx) { + LOG_ERR("%s: def_dev_ctx is NULL", + __func__); + goto unlock; + } + + if (type == ETHERNET_CONFIG_TYPE_TXINJECTION_MODE) { + config->txinjection_mode = + def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->txinjection_mode; + } + ret = 0; +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +out: +#endif + return ret; +} + +int nrf_wifi_if_set_config_zep(const struct device *dev, + enum ethernet_config_type type, + const struct ethernet_config *config) +{ + 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; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + int ret = -1; + + if (!dev) { + LOG_ERR("%s: Invalid parameters", + __func__); + goto out; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", + __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + /* Commands without FMAC interaction */ + if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) { + if (!net_eth_is_addr_valid((struct net_eth_addr *)&config->mac_address)) { + LOG_ERR("%s: Invalid MAC address", + __func__); + goto unlock; + } + memcpy(vif_ctx_zep->mac_addr.addr, + config->mac_address.addr, + sizeof(vif_ctx_zep->mac_addr.addr)); + + net_if_set_link_addr(vif_ctx_zep->zep_net_if_ctx, + vif_ctx_zep->mac_addr.addr, + sizeof(vif_ctx_zep->mac_addr.addr), + NET_LINK_ETHERNET); + ret = 0; + goto unlock; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: rpu_ctx_zep or rpu_ctx is NULL", + __func__); + goto unlock; + } + + fmac_dev_ctx = rpu_ctx_zep->rpu_ctx; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + if (!def_dev_ctx) { + LOG_ERR("%s: def_dev_ctx is NULL", + __func__); + goto unlock; + } + +#ifdef CONFIG_NRF70_RAW_DATA_TX + if (type == ETHERNET_CONFIG_TYPE_TXINJECTION_MODE) { + unsigned char mode; + + if (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->txinjection_mode == + config->txinjection_mode) { + LOG_INF("%s: Driver TX injection setting is same as configured setting", + __func__); + goto unlock; + } + /** + * Since UMAC wishes to use the same mode command as previously + * used for mode, `OR` the primary mode with TX-Injection mode and + * send it to the UMAC. That way UMAC can still maintain code + * as is + */ + if (config->txinjection_mode) { + mode = (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode) | + (NRF_WIFI_TX_INJECTION_MODE); + } else { + mode = (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode) ^ + (NRF_WIFI_TX_INJECTION_MODE); + } + + ret = nrf_wifi_fmac_set_mode(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, mode); + + if (ret != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Mode set operation failed", __func__); + goto unlock; + } + } +#endif +#ifdef CONFIG_NRF70_PROMISC_DATA_RX + else if (type == ETHERNET_CONFIG_TYPE_PROMISC_MODE) { + unsigned char mode; + + if (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->promisc_mode == + config->promisc_mode) { + LOG_ERR("%s: Driver promisc mode setting is same as configured setting", + __func__); + goto out; + } + + if (config->promisc_mode) { + mode = (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode) | + (NRF_WIFI_PROMISCUOUS_MODE); + } else { + mode = (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode) ^ + (NRF_WIFI_PROMISCUOUS_MODE); + } + + ret = nrf_wifi_fmac_set_mode(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, mode); + + if (ret != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: mode set operation failed", __func__); + goto out; + } + } +#endif + ret = 0; +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +out: + return ret; +} + +#ifdef CONFIG_NET_STATISTICS_ETHERNET +struct net_stats_eth *nrf_wifi_eth_stats_get(const struct device *dev) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!dev) { + LOG_ERR("%s Device not found", __func__); + goto out; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + goto out; + } + + return &vif_ctx_zep->eth_stats; +out: + return NULL; +} +#endif /* CONFIG_NET_STATISTICS_ETHERNET */ + +#ifdef CONFIG_NET_STATISTICS_WIFI +int nrf_wifi_stats_get(const struct device *dev, struct net_stats_wifi *zstats) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; +#ifdef CONFIG_NRF70_RAW_DATA_TX + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; +#endif /* CONFIG_NRF70_RAW_DATA_TX */ + struct rpu_op_stats stats; + int ret = -1; + + if (!dev) { + LOG_ERR("%s Device not found", __func__); + goto out; + } + + if (!zstats) { + LOG_ERR("%s Stats buffer not allocated", __func__); + goto out; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: rpu_ctx_zep or rpu_ctx is NULL", + __func__); + goto unlock; + } + + memset(&stats, 0, sizeof(struct rpu_op_stats)); + status = nrf_wifi_fmac_stats_get(rpu_ctx_zep->rpu_ctx, 0, &stats); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_stats_get failed", __func__); + goto unlock; + } + + zstats->pkts.tx = stats.host.total_tx_pkts; + zstats->pkts.rx = stats.host.total_rx_pkts; + zstats->errors.tx = stats.host.total_tx_drop_pkts; + zstats->errors.rx = stats.host.total_rx_drop_pkts + + stats.fw.umac.interface_data_stats.rx_checksum_error_count; + zstats->bytes.received = stats.fw.umac.interface_data_stats.rx_bytes; + zstats->bytes.sent = stats.fw.umac.interface_data_stats.tx_bytes; + zstats->sta_mgmt.beacons_rx = stats.fw.umac.interface_data_stats.rx_beacon_success_count; + zstats->sta_mgmt.beacons_miss = stats.fw.umac.interface_data_stats.rx_beacon_miss_count; + zstats->broadcast.rx = stats.fw.umac.interface_data_stats.rx_broadcast_pkt_count; + zstats->broadcast.tx = stats.fw.umac.interface_data_stats.tx_broadcast_pkt_count; + zstats->multicast.rx = stats.fw.umac.interface_data_stats.rx_multicast_pkt_count; + zstats->multicast.tx = stats.fw.umac.interface_data_stats.tx_multicast_pkt_count; + zstats->unicast.rx = stats.fw.umac.interface_data_stats.rx_unicast_pkt_count; + zstats->unicast.tx = stats.fw.umac.interface_data_stats.tx_unicast_pkt_count; + +#ifdef CONFIG_NRF70_RAW_DATA_TX + def_dev_ctx = wifi_dev_priv(rpu_ctx_zep->rpu_ctx); + zstats->errors.tx += def_dev_ctx->raw_pkt_stats.raw_pkt_send_failure; +#endif /* CONFIG_NRF70_RAW_DATA_TX */ + ret = 0; +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +out: + return ret; +} + +int nrf_wifi_stats_reset(const struct device *dev) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + int ret = -1; + + if (!dev) { + LOG_ERR("%s Device not found", __func__); + goto out; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + goto out; + } + + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (ret != 0) { + LOG_ERR("%s: Failed to lock vif_lock", __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: rpu_ctx_zep or rpu_ctx is NULL", + __func__); + goto unlock; + } + + status = nrf_wifi_fmac_stats_reset(rpu_ctx_zep->rpu_ctx); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_stats_reset failed", __func__); + goto unlock; + } + + def_dev_ctx = wifi_dev_priv(rpu_ctx_zep->rpu_ctx); + memset(&def_dev_ctx->host_stats, 0, sizeof(struct rpu_host_stats)); + + ret = 0; +unlock: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +out: + return ret; +} +#endif /* CONFIG_NET_STATISTICS_WIFI */ diff --git a/drivers/wifi/nrfwifi/src/qspi/inc/ficr_prog.h b/drivers/wifi/nrfwifi/src/qspi/inc/ficr_prog.h new file mode 100644 index 000000000000..35c4bda1fa32 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/inc/ficr_prog.h @@ -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 +#include + +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_ */ diff --git a/drivers/wifi/nrfwifi/src/qspi/inc/qspi_if.h b/drivers/wifi/nrfwifi/src/qspi/inc/qspi_if.h new file mode 100644 index 000000000000..e66db6c48369 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/inc/qspi_if.h @@ -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 +#include +#ifdef CONFIG_NRF70_ON_QSPI +#include +#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__ */ diff --git a/drivers/wifi/nrfwifi/src/qspi/inc/rpu_hw_if.h b/drivers/wifi/nrfwifi/src/qspi/inc/rpu_hw_if.h new file mode 100644 index 000000000000..2524b64ab505 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/inc/rpu_hw_if.h @@ -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 +#include +#include + +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_ */ diff --git a/drivers/wifi/nrfwifi/src/qspi/inc/spi_if.h b/drivers/wifi/nrfwifi/src/qspi/inc/spi_if.h new file mode 100644 index 000000000000..2f64bd2c262a --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/inc/spi_if.h @@ -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); diff --git a/drivers/wifi/nrfwifi/src/qspi/inc/spi_nor.h b/drivers/wifi/nrfwifi/src/qspi/inc/spi_nor.h new file mode 100644 index 000000000000..3d56f348d24c --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/inc/spi_nor.h @@ -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 + +#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__*/ diff --git a/drivers/wifi/nrfwifi/src/qspi/src/device.c b/drivers/wifi/nrfwifi/src/qspi/src/device.c new file mode 100644 index 000000000000..4acbaf3861fc --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/src/device.c @@ -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 +#include +#include +#include +#include + +#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 +} diff --git a/drivers/wifi/nrfwifi/src/qspi/src/ficr_prog.c b/drivers/wifi/nrfwifi/src/qspi/src/ficr_prog.c new file mode 100644 index 000000000000..5558b35e8374 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/src/ficr_prog.c @@ -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 +#include +#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(); +} diff --git a/drivers/wifi/nrfwifi/src/qspi/src/qspi_if.c b/drivers/wifi/nrfwifi/src/qspi/src/qspi_if.c new file mode 100644 index 000000000000..29fadd940302 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/src/qspi_if.c @@ -0,0 +1,1361 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief File containing QSPI device interface specific definitions for the + * Zephyr OS layer of the Wi-Fi driver. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "spi_nor.h" +#include "qspi_if.h" + +/* The QSPI bus node which the NRF70 is on */ +#define QSPI_IF_BUS_NODE DT_NODELABEL(qspi) + +/* QSPI bus properties from the devicetree */ +#define QSPI_IF_BUS_IRQN DT_IRQN(QSPI_IF_BUS_NODE) +#define QSPI_IF_BUS_IRQ_PRIO DT_IRQ(QSPI_IF_BUS_NODE, priority) +#define QSPI_IF_BUS_SCK_PIN DT_PROP(QSPI_IF_BUS_NODE, sck_pin) +#define QSPI_IF_BUS_CSN_PIN DT_PROP(QSPI_IF_BUS_NODE, csn_pins) +#define QSPI_IF_BUS_IO0_PIN DT_PROP_BY_IDX(QSPI_IF_BUS_NODE, io_pins, 0) +#define QSPI_IF_BUS_IO1_PIN DT_PROP_BY_IDX(QSPI_IF_BUS_NODE, io_pins, 1) +#define QSPI_IF_BUS_IO2_PIN DT_PROP_BY_IDX(QSPI_IF_BUS_NODE, io_pins, 2) +#define QSPI_IF_BUS_IO3_PIN DT_PROP_BY_IDX(QSPI_IF_BUS_NODE, io_pins, 3) + +#define QSPI_IF_BUS_HAS_4_IO_PINS \ + (DT_PROP_LEN(QSPI_IF_BUS_NODE, io_pins) == 4) + +#define QSPI_IF_BUS_PINCTRL_DT_DEV_CONFIG_GET \ + PINCTRL_DT_DEV_CONFIG_GET(QSPI_IF_BUS_NODE) + +/* The NRF70 device node which is on the QSPI bus */ +#define QSPI_IF_DEVICE_NODE DT_NODELABEL(nrf70) + +/* NRF70 device QSPI properties */ +#define QSPI_IF_DEVICE_FREQUENCY DT_PROP(QSPI_IF_DEVICE_NODE, qspi_frequency) +#define QSPI_IF_DEVICE_CPHA DT_PROP(QSPI_IF_DEVICE_NODE, qspi_cpha) +#define QSPI_IF_DEVICE_CPOL DT_PROP(QSPI_IF_DEVICE_NODE, qspi_cpol) +#define QSPI_IF_DEVICE_QUAD_MODE DT_PROP(QSPI_IF_DEVICE_NODE, qspi_quad_mode) +#define QSPI_IF_DEVICE_RX_DELAY DT_PROP(QSPI_IF_DEVICE_NODE, qspi_rx_delay) + +static struct qspi_config *qspi_cfg; +#if NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC +static unsigned int nonce_last_addr; +static unsigned int nonce_cnt; +#endif /*NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC*/ + +/* Main config structure */ +static nrfx_qspi_config_t QSPIconfig; + +/* + * According to the respective specifications, the nRF52 QSPI supports clock + * frequencies 2 - 32 MHz and the nRF53 one supports 6 - 96 MHz. + */ +BUILD_ASSERT(QSPI_IF_DEVICE_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 16), + "Unsupported SCK frequency."); + +/* + * Determine a configuration value (INST_0_SCK_CFG) and, if needed, a divider + * (BASE_CLOCK_DIV) for the clock from which the SCK frequency is derived that + * need to be used to achieve the SCK frequency as close as possible (but not + * higher) to the one specified in DT. + */ +#if defined(CONFIG_SOC_SERIES_NRF53X) +/* + * On nRF53 Series SoCs, the default /4 divider for the HFCLK192M clock can + * only be used when the QSPI peripheral is idle. When a QSPI operation is + * performed, the divider needs to be changed to /1 or /2 (particularly, + * the specification says that the peripheral "supports 192 MHz and 96 MHz + * PCLK192M frequency"), but after that operation is complete, the default + * divider needs to be restored to avoid increased current consumption. + */ +#if (INST_0_SCK_FREQUENCY >= NRF_QSPI_BASE_CLOCK_FREQ) +/* For requested SCK >= 96 MHz, use HFCLK192M / 1 / (2*1) = 96 MHz */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_1 +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV1 +/* If anomaly 159 is to be prevented, only /1 divider can be used. */ +#elif NRF53_ERRATA_159_ENABLE_WORKAROUND +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_1 +#define INST_0_SCK_CFG (DIV_ROUND_UP(NRF_QSPI_BASE_CLOCK_FREQ, \ + INST_0_SCK_FREQUENCY) - 1) +#elif (INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 2)) +/* For 96 MHz > SCK >= 48 MHz, use HFCLK192M / 2 / (2*1) = 48 MHz */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_2 +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV1 +#elif (INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 3)) +/* For 48 MHz > SCK >= 32 MHz, use HFCLK192M / 1 / (2*3) = 32 MHz */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_1 +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV3 +#else +/* For requested SCK < 32 MHz, use divider /2 for HFCLK192M. */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_2 +#define INST_0_SCK_CFG (DIV_ROUND_UP(NRF_QSPI_BASE_CLOCK_FREQ / 2, \ + QSPI_IF_DEVICE_FREQUENCY) - 1) +#endif + +#if BASE_CLOCK_DIV == NRF_CLOCK_HFCLK_DIV_1 +/* For 8 MHz, use HFCLK192M / 1 / (2*12) */ +#define INST_0_SCK_CFG_WAKE NRF_QSPI_FREQ_DIV12 +#elif BASE_CLOCK_DIV == NRF_CLOCK_HFCLK_DIV_2 +/* For 8 MHz, use HFCLK192M / 2 / (2*6) */ +#define INST_0_SCK_CFG_WAKE NRF_QSPI_FREQ_DIV6 +#else +#error "Unsupported base clock divider for wake-up frequency." +#endif + +/* After the base clock divider is changed, some time is needed for the new + * setting to take effect. This value specifies the delay (in microseconds) + * to be applied to ensure that the clock is ready when the QSPI operation + * starts. It was measured with a logic analyzer (unfortunately, the nRF5340 + * specification does not provide any numbers in this regard). + */ +#define BASE_CLOCK_SWITCH_DELAY_US 7 + +#else +/* + * On nRF52 Series SoCs, the base clock divider is not configurable, + * so BASE_CLOCK_DIV is not defined. + */ +#if (QSPI_IF_DEVICE_FREQUENCY >= NRF_QSPI_BASE_CLOCK_FREQ) +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV1 +#else +#define INST_0_SCK_CFG (DIV_ROUND_UP(NRF_QSPI_BASE_CLOCK_FREQ, \ + QSPI_IF_DEVICE_FREQUENCY) - 1) +#endif + +/* For 8 MHz, use PCLK32M / 4 */ +#define INST_0_SCK_CFG_WAKE NRF_QSPI_FREQ_DIV4 + +#endif /* defined(CONFIG_SOC_SERIES_NRF53X) */ + +static int qspi_device_init(const struct device *dev); +static void qspi_device_uninit(const struct device *dev); + +#define WORD_SIZE 4 + +LOG_MODULE_DECLARE(wifi_nrf_bus, CONFIG_WIFI_NRF70_BUS_LOG_LEVEL); + +/** + * @brief QSPI buffer structure + * Structure used both for TX and RX purposes. + * + * @param buf is a valid pointer to a data buffer. + * Can not be NULL. + * @param len is the length of the data to be handled. + * If no data to transmit/receive - pass 0. + */ +struct qspi_buf { + uint8_t *buf; + size_t len; +}; + +/** + * @brief QSPI command structure + * Structure used for custom command usage. + * + * @param op_code is a command value (i.e 0x9F - get Jedec ID) + * @param tx_buf structure used for TX purposes. Can be NULL if not used. + * @param rx_buf structure used for RX purposes. Can be NULL if not used. + */ +struct qspi_cmd { + uint8_t op_code; + const struct qspi_buf *tx_buf; + const struct qspi_buf *rx_buf; +}; + +/** + * @brief Structure for defining the QSPI NOR access + */ +struct qspi_nor_data { +#ifdef CONFIG_MULTITHREADING + /* The semaphore to control exclusive access on write/erase. */ + struct k_sem trans; + /* The semaphore to control exclusive access to the device. */ + struct k_sem sem; + /* The semaphore to indicate that transfer has completed. */ + struct k_sem sync; + /* The semaphore to control driver init/uninit. */ + struct k_sem count; +#else /* CONFIG_MULTITHREADING */ + /* A flag that signals completed transfer when threads are + * not enabled. + */ + volatile bool ready; +#endif /* CONFIG_MULTITHREADING */ +}; + +static inline int qspi_get_mode(bool cpol, bool cpha) +{ + register int ret = -EINVAL; + + if ((!cpol) && (!cpha)) + ret = 0; + else if (cpol && cpha) + ret = 1; + + __ASSERT(ret != -EINVAL, "Invalid QSPI mode"); + + return ret; +} + +static inline bool qspi_write_is_quad(nrf_qspi_writeoc_t lines) +{ + switch (lines) { + case NRF_QSPI_WRITEOC_PP4IO: + case NRF_QSPI_WRITEOC_PP4O: + return true; + default: + return false; + } +} + +static inline bool qspi_read_is_quad(nrf_qspi_readoc_t lines) +{ + switch (lines) { + case NRF_QSPI_READOC_READ4IO: + case NRF_QSPI_READOC_READ4O: + return true; + default: + return false; + } +} + +static inline int qspi_get_lines_write(uint8_t lines) +{ + register int ret = -EINVAL; + + switch (lines) { + case 3: + ret = NRF_QSPI_WRITEOC_PP4IO; + break; + case 2: + ret = NRF_QSPI_WRITEOC_PP4O; + break; + case 1: + ret = NRF_QSPI_WRITEOC_PP2O; + break; + case 0: + ret = NRF_QSPI_WRITEOC_PP; + break; + default: + break; + } + + __ASSERT(ret != -EINVAL, "Invalid QSPI write line"); + + return ret; +} + +static inline int qspi_get_lines_read(uint8_t lines) +{ + register int ret = -EINVAL; + + switch (lines) { + case 4: + ret = NRF_QSPI_READOC_READ4IO; + break; + case 3: + ret = NRF_QSPI_READOC_READ4O; + break; + case 2: + ret = NRF_QSPI_READOC_READ2IO; + break; + case 1: + ret = NRF_QSPI_READOC_READ2O; + break; + case 0: + ret = NRF_QSPI_READOC_FASTREAD; + break; + default: + break; + } + + __ASSERT(ret != -EINVAL, "Invalid QSPI read line"); + + return ret; +} + +nrfx_err_t _nrfx_qspi_read(void *p_rx_buffer, size_t rx_buffer_length, uint32_t src_address) +{ + return nrfx_qspi_read(p_rx_buffer, rx_buffer_length, src_address); +} + +nrfx_err_t _nrfx_qspi_write(void const *p_tx_buffer, size_t tx_buffer_length, uint32_t dst_address) +{ + return nrfx_qspi_write(p_tx_buffer, tx_buffer_length, dst_address); +} + +nrfx_err_t _nrfx_qspi_init(nrfx_qspi_config_t const *p_config, nrfx_qspi_handler_t handler, + void *p_context) +{ + NRF_QSPI_Type *p_reg = NRF_QSPI; + + nrfx_qspi_init(p_config, handler, p_context); + + /* RDC4IO = 4'hA (register IFTIMING), which means 10 Dummy Cycles for READ4. */ + p_reg->IFTIMING |= qspi_cfg->RDC4IO; + + /* LOG_DBG("%04x : IFTIMING", p_reg->IFTIMING & qspi_cfg->RDC4IO); */ + + /* ACTIVATE task fails for slave bitfile so ignore it */ + return NRFX_SUCCESS; +} + + +/** + * @brief Main configuration structure + */ +static struct qspi_nor_data qspi_nor_memory_data = { +#ifdef CONFIG_MULTITHREADING + .trans = Z_SEM_INITIALIZER(qspi_nor_memory_data.trans, 1, 1), + .sem = Z_SEM_INITIALIZER(qspi_nor_memory_data.sem, 1, 1), + .sync = Z_SEM_INITIALIZER(qspi_nor_memory_data.sync, 0, 1), + .count = Z_SEM_INITIALIZER(qspi_nor_memory_data.count, 0, K_SEM_MAX_LIMIT), +#endif /* CONFIG_MULTITHREADING */ +}; + +NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(QSPI_IF_BUS_NODE); + +IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_DEFINE(QSPI_IF_BUS_NODE))); + +/** + * @brief Converts NRFX return codes to the zephyr ones + */ +static inline int qspi_get_zephyr_ret_code(nrfx_err_t res) +{ + switch (res) { + case NRFX_SUCCESS: + return 0; + case NRFX_ERROR_INVALID_PARAM: + case NRFX_ERROR_INVALID_ADDR: + return -EINVAL; + case NRFX_ERROR_INVALID_STATE: + return -ECANCELED; +#if NRF53_ERRATA_159_ENABLE_WORKAROUND + case NRFX_ERROR_FORBIDDEN: + LOG_ERR("nRF5340 anomaly 159 conditions detected"); + LOG_ERR("Set the CPU clock to 64 MHz before starting QSPI operation"); + return -ECANCELED; +#endif + case NRFX_ERROR_BUSY: + case NRFX_ERROR_TIMEOUT: + default: + return -EBUSY; + } +} + +static inline struct qspi_nor_data *get_dev_data(const struct device *dev) +{ + return dev->data; +} + +static inline void qspi_lock(const struct device *dev) +{ +#ifdef CONFIG_MULTITHREADING + struct qspi_nor_data *dev_data = get_dev_data(dev); + + k_sem_take(&dev_data->sem, K_FOREVER); +#else /* CONFIG_MULTITHREADING */ + ARG_UNUSED(dev); +#endif /* CONFIG_MULTITHREADING */ + + /* + * Change the base clock divider only for the time the driver is locked + * to perform a QSPI operation, otherwise the power consumption would be + * increased also when the QSPI peripheral is idle. + */ +#if defined(CONFIG_SOC_SERIES_NRF53X) + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); + k_busy_wait(BASE_CLOCK_SWITCH_DELAY_US); +#endif +} + +static inline void qspi_unlock(const struct device *dev) +{ +#if defined(CONFIG_SOC_SERIES_NRF53X) + /* Restore the default base clock divider to reduce power consumption. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); + k_busy_wait(BASE_CLOCK_SWITCH_DELAY_US); +#endif + +#ifdef CONFIG_MULTITHREADING + struct qspi_nor_data *dev_data = get_dev_data(dev); + + k_sem_give(&dev_data->sem); +#else /* CONFIG_MULTITHREADING */ + ARG_UNUSED(dev); +#endif /* CONFIG_MULTITHREADING */ +} + +static inline void qspi_trans_lock(const struct device *dev) +{ +#ifdef CONFIG_MULTITHREADING + struct qspi_nor_data *dev_data = get_dev_data(dev); + + k_sem_take(&dev_data->trans, K_FOREVER); +#else /* CONFIG_MULTITHREADING */ + ARG_UNUSED(dev); +#endif /* CONFIG_MULTITHREADING */ +} + +static inline void qspi_trans_unlock(const struct device *dev) +{ +#ifdef CONFIG_MULTITHREADING + struct qspi_nor_data *dev_data = get_dev_data(dev); + + k_sem_give(&dev_data->trans); +#else /* CONFIG_MULTITHREADING */ + ARG_UNUSED(dev); +#endif /* CONFIG_MULTITHREADING */ +} + +static inline void qspi_wait_for_completion(const struct device *dev, nrfx_err_t res) +{ + struct qspi_nor_data *dev_data = get_dev_data(dev); + + if (res == NRFX_SUCCESS) { +#ifdef CONFIG_MULTITHREADING + k_sem_take(&dev_data->sync, K_FOREVER); +#else /* CONFIG_MULTITHREADING */ + unsigned int key = irq_lock(); + + while (!dev_data->ready) { + k_cpu_atomic_idle(key); + key = irq_lock(); + } + + dev_data->ready = false; + irq_unlock(key); +#endif /* CONFIG_MULTITHREADING */ + } +} + +static inline void qspi_complete(struct qspi_nor_data *dev_data) +{ +#ifdef CONFIG_MULTITHREADING + k_sem_give(&dev_data->sync); +#else /* CONFIG_MULTITHREADING */ + dev_data->ready = true; +#endif /* CONFIG_MULTITHREADING */ +} + +static inline void _qspi_complete(struct qspi_nor_data *dev_data) +{ + if (!qspi_cfg->easydma) + return; + + qspi_complete(dev_data); +} +static inline void _qspi_wait_for_completion(const struct device *dev, nrfx_err_t res) +{ + if (!qspi_cfg->easydma) + return; + + qspi_wait_for_completion(dev, res); +} + +/** + * @brief QSPI handler + * + * @param event Driver event type + * @param p_context Pointer to context. Use in interrupt handler. + * @retval None + */ +static void qspi_handler(nrfx_qspi_evt_t event, void *p_context) +{ + struct qspi_nor_data *dev_data = p_context; + + if (event == NRFX_QSPI_EVENT_DONE) + _qspi_complete(dev_data); +} + +static bool qspi_initialized; + +static int qspi_device_init(const struct device *dev) +{ + struct qspi_nor_data *dev_data = get_dev_data(dev); + nrfx_err_t res; + int ret = 0; + + if (!IS_ENABLED(CONFIG_NRF70_QSPI_LOW_POWER)) { + return 0; + } + + qspi_lock(dev); + + /* In multithreading, driver can call qspi_device_init more than once + * before calling qspi_device_uninit. Keepping count, so QSPI is + * uninitialized only at the last call (count == 0). + */ +#ifdef CONFIG_MULTITHREADING + k_sem_give(&dev_data->count); +#endif + + if (!qspi_initialized) { + res = nrfx_qspi_init(&QSPIconfig, qspi_handler, dev_data); + ret = qspi_get_zephyr_ret_code(res); + NRF_QSPI->IFTIMING |= qspi_cfg->RDC4IO; + qspi_initialized = (ret == 0); + } + + qspi_unlock(dev); + + return ret; +} + +static void qspi_device_uninit(const struct device *dev) +{ + bool last = true; + + if (!IS_ENABLED(CONFIG_NRF70_QSPI_LOW_POWER)) { + return; + } + + qspi_lock(dev); + +#ifdef CONFIG_MULTITHREADING + struct qspi_nor_data *dev_data = get_dev_data(dev); + + /* The last thread to finish using the driver uninit the QSPI */ + (void)k_sem_take(&dev_data->count, K_NO_WAIT); + last = (k_sem_count_get(&dev_data->count) == 0); +#endif + + if (last) { + while (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) { + if (IS_ENABLED(CONFIG_MULTITHREADING)) + k_msleep(50); + else + k_busy_wait(50000); + } + + nrfx_qspi_uninit(); + +#ifndef CONFIG_PINCTRL + nrf_gpio_cfg_output(QSPI_PROP_AT(csn_pins, 0)); + nrf_gpio_pin_set(QSPI_PROP_AT(csn_pins, 0)); +#endif + + qspi_initialized = false; + } + + qspi_unlock(dev); +} + +/* QSPI send custom command. + * + * If this is used for both send and receive the buffer sizes must be + * equal and cover the whole transaction. + */ +static int qspi_send_cmd(const struct device *dev, const struct qspi_cmd *cmd, bool wren) +{ + /* Check input parameters */ + if (!cmd) + return -EINVAL; + + const void *tx_buf = NULL; + size_t tx_len = 0; + void *rx_buf = NULL; + size_t rx_len = 0; + size_t xfer_len = sizeof(cmd->op_code); + + if (cmd->tx_buf) { + tx_buf = cmd->tx_buf->buf; + tx_len = cmd->tx_buf->len; + } + + if (cmd->rx_buf) { + rx_buf = cmd->rx_buf->buf; + rx_len = cmd->rx_buf->len; + } + + if ((rx_len != 0) && (tx_len != 0)) { + if (rx_len != tx_len) + return -EINVAL; + + xfer_len += tx_len; + } else + /* At least one of these is zero. */ + xfer_len += tx_len + rx_len; + + if (xfer_len > NRF_QSPI_CINSTR_LEN_9B) { + LOG_WRN("cinstr %02x transfer too long: %zu", cmd->op_code, xfer_len); + + return -EINVAL; + } + + nrf_qspi_cinstr_conf_t cinstr_cfg = { + .opcode = cmd->op_code, + .length = xfer_len, + .io2_level = true, + .io3_level = true, + .wipwait = false, + .wren = wren, + }; + + qspi_lock(dev); + + int res = nrfx_qspi_cinstr_xfer(&cinstr_cfg, tx_buf, rx_buf); + + qspi_unlock(dev); + return qspi_get_zephyr_ret_code(res); +} + +/* RDSR wrapper. Negative value is error. */ +static int qspi_rdsr(const struct device *dev) +{ + uint8_t sr = -1; + const struct qspi_buf sr_buf = { + .buf = &sr, + .len = sizeof(sr), + }; + struct qspi_cmd cmd = { + .op_code = SPI_NOR_CMD_RDSR, + .rx_buf = &sr_buf, + }; + int ret = qspi_send_cmd(dev, &cmd, false); + + return (ret < 0) ? ret : sr; +} + +/* Wait until RDSR confirms write is not in progress. */ +static int qspi_wait_while_writing(const struct device *dev) +{ + int ret; + + do { + ret = qspi_rdsr(dev); + } while ((ret >= 0) && ((ret & SPI_NOR_WIP_BIT) != 0U)); + + return (ret < 0) ? ret : 0; +} + +/** + * @brief Fills init struct + * + * @param config Pointer to the config struct provided by user + * @param initstruct Pointer to the configuration struct + * @retval None + */ +static inline void qspi_fill_init_struct(nrfx_qspi_config_t *initstruct) +{ + /* Configure XIP offset */ + initstruct->xip_offset = 0; + +#ifdef CONFIG_PINCTRL + initstruct->skip_gpio_cfg = true, + initstruct->skip_psel_cfg = true, +#else + /* Configure pins */ + initstruct->pins.sck_pin = QSPI_IF_BUS_SCK_PIN; + initstruct->pins.csn_pin = QSPI_IF_BUS_CSN_PIN; + initstruct->pins.io0_pin = QSPI_IF_BUS_IO0_PIN; + initstruct->pins.io1_pin = QSPI_IF_BUS_IO1_PIN; +#if QSPI_IF_BUS_HAS_4_IO_PINS + initstruct->pins.io2_pin = QSPI_IF_BUS_IO2_PIN; + initstruct->pins.io3_pin = QSPI_IF_BUS_IO3_PIN; +#else + initstruct->pins.io2_pin = NRF_QSPI_PIN_NOT_CONNECTED; + initstruct->pins.io3_pin = NRF_QSPI_PIN_NOT_CONNECTED; +#endif +#endif /* CONFIG_PINCTRL */ + /* Configure Protocol interface */ + initstruct->prot_if.addrmode = NRF_QSPI_ADDRMODE_24BIT; + + initstruct->prot_if.dpmconfig = false; + + /* Configure physical interface */ + initstruct->phy_if.sck_freq = INST_0_SCK_CFG; + + /* Using MHZ fails checkpatch constant check */ + if (QSPI_IF_DEVICE_FREQUENCY >= 16000000) { + qspi_cfg->qspi_slave_latency = 1; + } + initstruct->phy_if.sck_delay = QSPI_IF_DEVICE_RX_DELAY; + initstruct->phy_if.spi_mode = qspi_get_mode(QSPI_IF_DEVICE_CPOL, QSPI_IF_DEVICE_CPHA); + + if (QSPI_IF_DEVICE_QUAD_MODE) { + initstruct->prot_if.readoc = NRF_QSPI_READOC_READ4IO; + initstruct->prot_if.writeoc = NRF_QSPI_WRITEOC_PP4IO; + } else { + initstruct->prot_if.readoc = NRF_QSPI_READOC_FASTREAD; + initstruct->prot_if.writeoc = NRF_QSPI_WRITEOC_PP; + } + + initstruct->phy_if.dpmen = false; +} + +/* Configures QSPI memory for the transfer */ +static int qspi_nrfx_configure(const struct device *dev) +{ + if (!dev) + return -ENXIO; + + struct qspi_nor_data *dev_data = dev->data; + + qspi_fill_init_struct(&QSPIconfig); + +#if defined(CONFIG_SOC_SERIES_NRF53X) + /* When the QSPI peripheral is activated, during the nrfx_qspi driver + * initialization, it reads the status of the connected flash chip. + * Make sure this transaction is performed with a valid base clock + * divider. + */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); + k_busy_wait(BASE_CLOCK_SWITCH_DELAY_US); +#endif + + nrfx_err_t res = _nrfx_qspi_init(&QSPIconfig, qspi_handler, dev_data); + +#if defined(CONFIG_SOC_SERIES_NRF53X) + /* Restore the default /4 divider after the QSPI initialization. */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); + k_busy_wait(BASE_CLOCK_SWITCH_DELAY_US); +#endif + + int ret = qspi_get_zephyr_ret_code(res); + + if (ret == 0) { + /* Set QE to match transfer mode. If not using quad + * it's OK to leave QE set, but doing so prevents use + * of WP#/RESET#/HOLD# which might be useful. + * + * Note build assert above ensures QER is S1B6. Other + * options require more logic. + */ + ret = qspi_rdsr(dev); + + if (ret < 0) { + LOG_ERR("RDSR failed: %d", ret); + return ret; + } + + uint8_t sr = (uint8_t)ret; + bool qe_value = (qspi_write_is_quad(QSPIconfig.prot_if.writeoc)) || + (qspi_read_is_quad(QSPIconfig.prot_if.readoc)); + const uint8_t qe_mask = BIT(6); /* only S1B6 */ + bool qe_state = ((sr & qe_mask) != 0U); + + LOG_DBG("RDSR %02x QE %d need %d: %s", sr, qe_state, qe_value, + (qe_state != qe_value) ? "updating" : "no-change"); + + ret = 0; + + if (qe_state != qe_value) { + const struct qspi_buf sr_buf = { + .buf = &sr, + .len = sizeof(sr), + }; + struct qspi_cmd cmd = { + .op_code = SPI_NOR_CMD_WRSR, + .tx_buf = &sr_buf, + }; + + sr ^= qe_mask; + ret = qspi_send_cmd(dev, &cmd, true); + + /* Writing SR can take some time, and further + * commands sent while it's happening can be + * corrupted. Wait. + */ + if (ret == 0) + ret = qspi_wait_while_writing(dev); + } + + if (ret < 0) + LOG_ERR("QE %s failed: %d", qe_value ? "set" : "clear", ret); + } + + return ret; +} + +static inline nrfx_err_t read_non_aligned(const struct device *dev, int addr, void *dest, + size_t size) +{ + uint8_t __aligned(WORD_SIZE) buf[WORD_SIZE * 2]; + uint8_t *dptr = dest; + + int flash_prefix = (WORD_SIZE - (addr % WORD_SIZE)) % WORD_SIZE; + + if (flash_prefix > size) + flash_prefix = size; + + int dest_prefix = (WORD_SIZE - (int)dptr % WORD_SIZE) % WORD_SIZE; + + if (dest_prefix > size) + dest_prefix = size; + + int flash_suffix = (size - flash_prefix) % WORD_SIZE; + int flash_middle = size - flash_prefix - flash_suffix; + int dest_middle = size - dest_prefix - (size - dest_prefix) % WORD_SIZE; + + if (flash_middle > dest_middle) { + flash_middle = dest_middle; + flash_suffix = size - flash_prefix - flash_middle; + } + + nrfx_err_t res = NRFX_SUCCESS; + + /* read from aligned flash to aligned memory */ + if (flash_middle != 0) { + res = _nrfx_qspi_read(dptr + dest_prefix, flash_middle, addr + flash_prefix); + + _qspi_wait_for_completion(dev, res); + + if (res != NRFX_SUCCESS) + return res; + + /* perform shift in RAM */ + if (flash_prefix != dest_prefix) + memmove(dptr + flash_prefix, dptr + dest_prefix, flash_middle); + } + + /* read prefix */ + if (flash_prefix != 0) { + res = _nrfx_qspi_read(buf, WORD_SIZE, addr - (WORD_SIZE - flash_prefix)); + + _qspi_wait_for_completion(dev, res); + + if (res != NRFX_SUCCESS) + return res; + + memcpy(dptr, buf + WORD_SIZE - flash_prefix, flash_prefix); + } + + /* read suffix */ + if (flash_suffix != 0) { + res = _nrfx_qspi_read(buf, WORD_SIZE * 2, addr + flash_prefix + flash_middle); + + _qspi_wait_for_completion(dev, res); + + if (res != NRFX_SUCCESS) + return res; + + memcpy(dptr + flash_prefix + flash_middle, buf, flash_suffix); + } + + return res; +} + +static int qspi_nor_read(const struct device *dev, int addr, void *dest, size_t size) +{ + if (!dest) + return -EINVAL; + + /* read size must be non-zero */ + if (!size) + return 0; + + int rc = qspi_device_init(dev); + + if (rc != 0) + goto out; + + qspi_lock(dev); + + nrfx_err_t res = read_non_aligned(dev, addr, dest, size); + + qspi_unlock(dev); + + rc = qspi_get_zephyr_ret_code(res); + +out: + qspi_device_uninit(dev); + return rc; +} + +/* addr aligned, sptr not null, slen less than 4 */ +static inline nrfx_err_t write_sub_word(const struct device *dev, int addr, const void *sptr, + size_t slen) +{ + uint8_t __aligned(4) buf[4]; + nrfx_err_t res; + + /* read out the whole word so that unchanged data can be + * written back + */ + res = _nrfx_qspi_read(buf, sizeof(buf), addr); + _qspi_wait_for_completion(dev, res); + + if (res == NRFX_SUCCESS) { + memcpy(buf, sptr, slen); + res = _nrfx_qspi_write(buf, sizeof(buf), addr); + _qspi_wait_for_completion(dev, res); + } + + return res; +} + +static int qspi_nor_write(const struct device *dev, int addr, const void *src, size_t size) +{ + if (!src) + return -EINVAL; + + /* write size must be non-zero, less than 4, or a multiple of 4 */ + if ((size == 0) || ((size > 4) && ((size % 4U) != 0))) + return -EINVAL; + + /* address must be 4-byte aligned */ + if ((addr % 4U) != 0) + return -EINVAL; + + nrfx_err_t res = NRFX_SUCCESS; + + int rc = qspi_device_init(dev); + + if (rc != 0) + goto out; + + qspi_trans_lock(dev); + + qspi_lock(dev); + + if (size < 4U) + res = write_sub_word(dev, addr, src, size); + else { + res = _nrfx_qspi_write(src, size, addr); + _qspi_wait_for_completion(dev, res); + } + + qspi_unlock(dev); + + qspi_trans_unlock(dev); + + rc = qspi_get_zephyr_ret_code(res); +out: + qspi_device_uninit(dev); + return rc; +} + +/** + * @brief Configure the flash + * + * @param dev The flash device structure + * @param info The flash info structure + * @return 0 on success, negative errno code otherwise + */ +static int qspi_nor_configure(const struct device *dev) +{ + int ret = qspi_nrfx_configure(dev); + + if (ret != 0) + return ret; + + qspi_device_uninit(dev); + + return 0; +} + +/** + * @brief Initialize and configure the flash + * + * @param name The flash name + * @return 0 on success, negative errno code otherwise + */ +static int qspi_nor_init(const struct device *dev) +{ +#ifdef CONFIG_PINCTRL + int ret = pinctrl_apply_state(QSPI_IF_BUS_PINCTRL_DT_DEV_CONFIG_GET, + PINCTRL_STATE_DEFAULT); + + if (ret < 0) { + return ret; + } +#endif + + IRQ_CONNECT(QSPI_IF_BUS_IRQN, + QSPI_IF_BUS_IRQ_PRIO, + nrfx_isr, + nrfx_qspi_irq_handler, + 0); + + return qspi_nor_configure(dev); +} + +#if defined(CONFIG_SOC_SERIES_NRF53X) +static int qspi_cmd_encryption(const struct device *dev, nrf_qspi_encryption_t *p_cfg) +{ + const struct qspi_buf tx_buf = { .buf = (uint8_t *)&p_cfg->nonce[1], + .len = sizeof(p_cfg->nonce[1]) }; + const struct qspi_cmd cmd = { + .op_code = 0x4f, + .tx_buf = &tx_buf, + }; + + int ret = qspi_device_init(dev); + + if (ret == 0) + ret = qspi_send_cmd(dev, &cmd, false); + + qspi_device_uninit(dev); + + if (ret < 0) + LOG_DBG("cmd_encryption failed %d", ret); + + return ret; +} +#endif + +int qspi_RDSR2(const struct device *dev, uint8_t *rdsr2) +{ + int ret = 0; + uint8_t sr = 0; + + const struct qspi_buf sr_buf = { + .buf = &sr, + .len = sizeof(sr), + }; + struct qspi_cmd cmd = { + .op_code = 0x2f, + .rx_buf = &sr_buf, + }; + + ret = qspi_device_init(dev); + + ret = qspi_send_cmd(dev, &cmd, false); + + qspi_device_uninit(dev); + + LOG_DBG("RDSR2 = 0x%x", sr); + + if (ret == 0) + *rdsr2 = sr; + + return ret; +} + +/* Wait until RDSR2 confirms RPU_WAKE write is successful */ +int qspi_validate_rpu_wake_writecmd(const struct device *dev) +{ + int ret = 0; + uint8_t rdsr2 = 0; + + for (int ii = 0; ii < 1; ii++) { + ret = qspi_RDSR2(dev, &rdsr2); + if (!ret && (rdsr2 & RPU_WAKEUP_NOW)) { + return 0; + } + } + + return -1; +} + + +int qspi_RDSR1(const struct device *dev, uint8_t *rdsr1) +{ + int ret = 0; + uint8_t sr = 0; + + const struct qspi_buf sr_buf = { + .buf = &sr, + .len = sizeof(sr), + }; + struct qspi_cmd cmd = { + .op_code = 0x1f, + .rx_buf = &sr_buf, + }; + + ret = qspi_device_init(dev); + + ret = qspi_send_cmd(dev, &cmd, false); + + qspi_device_uninit(dev); + + LOG_DBG("RDSR1 = 0x%x", sr); + + if (ret == 0) + *rdsr1 = sr; + + return ret; +} + +/* Wait until RDSR1 confirms RPU_AWAKE/RPU_READY */ +int qspi_wait_while_rpu_awake(const struct device *dev) +{ + int ret; + uint8_t val = 0; + + for (int ii = 0; ii < 10; ii++) { + ret = qspi_RDSR1(dev, &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; + } + + /* Restore QSPI clock frequency from DTS */ + QSPIconfig.phy_if.sck_freq = INST_0_SCK_CFG; + + return val; +} + +int qspi_WRSR2(const struct device *dev, uint8_t data) +{ + const struct qspi_buf tx_buf = { + .buf = &data, + .len = sizeof(data), + }; + const struct qspi_cmd cmd = { + .op_code = 0x3f, + .tx_buf = &tx_buf, + }; + int ret = qspi_device_init(dev); + + if (ret == 0) + ret = qspi_send_cmd(dev, &cmd, false); + + qspi_device_uninit(dev); + + if (ret < 0) + LOG_ERR("cmd_wakeup RPU failed %d", ret); + + return ret; +} + +int qspi_cmd_wakeup_rpu(const struct device *dev, uint8_t data) +{ + int ret; + + /* Waking RPU works reliably only with lowest frequency (8MHz) */ + QSPIconfig.phy_if.sck_freq = INST_0_SCK_CFG_WAKE; + + ret = qspi_WRSR2(dev, data); + + return ret; +} + +struct device qspi_perip = { + .data = &qspi_nor_memory_data, +}; + +int qspi_deinit(void) +{ + LOG_DBG("TODO : %s", __func__); + + return 0; +} + +int qspi_init(struct qspi_config *config) +{ + unsigned int rc; + + qspi_cfg = config; + + config->readoc = config->quad_spi ? NRF_QSPI_READOC_READ4IO : NRF_QSPI_READOC_FASTREAD; + config->writeoc = config->quad_spi ? NRF_QSPI_WRITEOC_PP4IO : NRF_QSPI_WRITEOC_PP; + + rc = qspi_nor_init(&qspi_perip); + + k_sem_init(&qspi_cfg->lock, 1, 1); + + return rc; +} + +void qspi_update_nonce(unsigned int addr, int len, int hlread) +{ +#if NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC + + NRF_QSPI_Type *p_reg = NRF_QSPI; + + if (!qspi_cfg->encryption) + return; + + if (nonce_last_addr == 0 || hlread) + p_reg->DMA_ENC.NONCE2 = ++nonce_cnt; + else if ((nonce_last_addr + 4) != addr) + p_reg->DMA_ENC.NONCE2 = ++nonce_cnt; + + nonce_last_addr = addr + len - 4; + +#endif /*NRF_QSPI_HAS_XIP_ENC || NRF_QSPI_HAS_DMA_ENC*/ +} + +void qspi_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 qspi_write(unsigned int addr, const void *data, int len) +{ + int status; + + qspi_addr_check(addr, data, len); + + addr |= qspi_cfg->addrmask; + + k_sem_take(&qspi_cfg->lock, K_FOREVER); + + qspi_update_nonce(addr, len, 0); + + status = qspi_nor_write(&qspi_perip, addr, data, len); + + k_sem_give(&qspi_cfg->lock); + + return status; +} + +int qspi_read(unsigned int addr, void *data, int len) +{ + int status; + + qspi_addr_check(addr, data, len); + + addr |= qspi_cfg->addrmask; + + k_sem_take(&qspi_cfg->lock, K_FOREVER); + + qspi_update_nonce(addr, len, 0); + + status = qspi_nor_read(&qspi_perip, addr, data, len); + + k_sem_give(&qspi_cfg->lock); + + return status; +} + +int qspi_hl_readw(unsigned int addr, void *data) +{ + int status; + uint8_t *rxb = NULL; + uint32_t len = 4; + + len = len + (4 * qspi_cfg->qspi_slave_latency); + + rxb = k_malloc(len); + + if (rxb == NULL) { + LOG_ERR("%s: ERROR ENOMEM line %d", __func__, __LINE__); + return -ENOMEM; + } + + memset(rxb, 0, len); + + k_sem_take(&qspi_cfg->lock, K_FOREVER); + + qspi_update_nonce(addr, 4, 1); + + status = qspi_nor_read(&qspi_perip, addr, rxb, len); + + k_sem_give(&qspi_cfg->lock); + + *(uint32_t *)data = *(uint32_t *)(rxb + (len - 4)); + + k_free(rxb); + + return status; +} + +int qspi_hl_read(unsigned int addr, void *data, int len) +{ + int count = 0; + + qspi_addr_check(addr, data, len); + + while (count < (len / 4)) { + qspi_hl_readw(addr + (4 * count), ((char *)data + (4 * count))); + count++; + } + + return 0; +} + +int qspi_cmd_sleep_rpu(const struct device *dev) +{ + uint8_t data = 0x0; + + /* printf("TODO : %s:", __func__); */ + const struct qspi_buf tx_buf = { + .buf = &data, + .len = sizeof(data), + }; + + const struct qspi_cmd cmd = { + .op_code = 0x3f, /* 0x3f, //WRSR2(0x3F) WakeUP RPU. */ + .tx_buf = &tx_buf, + }; + + int ret = qspi_device_init(dev); + + if (ret == 0) { + ret = qspi_send_cmd(dev, &cmd, false); + } + + qspi_device_uninit(dev); + + if (ret < 0) { + LOG_ERR("cmd_wakeup RPU failed: %d", ret); + } + + return ret; +} + +/* Encryption public API */ + +int qspi_enable_encryption(uint8_t *key) +{ +#if defined(CONFIG_SOC_SERIES_NRF53X) + int err = 0; + + if (qspi_cfg->encryption) + return -EALREADY; + + int ret = qspi_device_init(&qspi_perip); + + if (ret != 0) { + LOG_ERR("qspi_device_init failed: %d", ret); + return -EIO; + } + + memcpy(qspi_cfg->p_cfg.key, key, 16); + + err = nrfx_qspi_dma_encrypt(&qspi_cfg->p_cfg); + if (err != NRFX_SUCCESS) { + LOG_ERR("nrfx_qspi_dma_encrypt failed: %d", err); + return -EIO; + } + + err = qspi_cmd_encryption(&qspi_perip, &qspi_cfg->p_cfg); + if (err != 0) { + LOG_ERR("qspi_cmd_encryption failed: %d", err); + return -EIO; + } + + qspi_cfg->encryption = true; + + qspi_device_uninit(&qspi_perip); + + return 0; +#else + return -ENOTSUP; +#endif +} diff --git a/drivers/wifi/nrfwifi/src/qspi/src/rpu_hw_if.c b/drivers/wifi/nrfwifi/src/qspi/src/rpu_hw_if.c new file mode 100644 index 000000000000..4ab65805e8ec --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/src/rpu_hw_if.c @@ -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 +#include + +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/wifi/nrfwifi/src/qspi/src/spi_if.c b/drivers/wifi/nrfwifi/src/qspi/src/spi_if.c new file mode 100644 index 000000000000..03ffa4657b97 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/qspi/src/spi_if.c @@ -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 + +#include +#include + +#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(); +} diff --git a/drivers/wifi/nrfwifi/src/shim.c b/drivers/wifi/nrfwifi/src/shim.c new file mode 100644 index 000000000000..4db264f9c963 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/shim.c @@ -0,0 +1,964 @@ +/* + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#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 +#include + +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); +} + +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, +}; diff --git a/drivers/wifi/nrfwifi/src/shim.h b/drivers/wifi/nrfwifi/src/shim.h new file mode 100644 index 000000000000..a4162bf89314 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/shim.h @@ -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 +#include +#include + +/** + * 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__ */ diff --git a/drivers/wifi/nrfwifi/src/timer.c b/drivers/wifi/nrfwifi/src/timer.c new file mode 100644 index 000000000000..c5928b901f85 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/timer.c @@ -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 +#include + +#include +#include +#include + +#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); +} diff --git a/drivers/wifi/nrfwifi/src/timer.h b/drivers/wifi/nrfwifi/src/timer.h new file mode 100644 index 000000000000..cb0fc6ff53bf --- /dev/null +++ b/drivers/wifi/nrfwifi/src/timer.h @@ -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__ */ diff --git a/drivers/wifi/nrfwifi/src/wifi_mgmt.c b/drivers/wifi/nrfwifi/src/wifi_mgmt.c new file mode 100644 index 000000000000..b18e893dcfbc --- /dev/null +++ b/drivers/wifi/nrfwifi/src/wifi_mgmt.c @@ -0,0 +1,1015 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief File containing WiFi management operation implementations + * for the Zephyr OS. + */ + +#include + +#include +#include + +#include "util.h" +#include "fmac_api.h" +#include "fmac_tx.h" +#include "fmac_util.h" +#include "fmac_main.h" +#include "wifi_mgmt.h" + +LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL); + +extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep; + +int nrf_wifi_set_power_save(const struct device *dev, + struct wifi_ps_params *params) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + int ret = -1; + unsigned int uapsd_queue = UAPSD_Q_MIN; /* Legacy mode */ + + if (!dev || !params) { + LOG_ERR("%s: dev or params is NULL", __func__); + return ret; + } + + vif_ctx_zep = dev->data; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __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; + } + + switch (params->type) { + case WIFI_PS_PARAM_LISTEN_INTERVAL: + if ((params->listen_interval < + NRF_WIFI_LISTEN_INTERVAL_MIN) || + (params->listen_interval > + WIFI_LISTEN_INTERVAL_MAX)) { + params->fail_reason = + WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID; + return -EINVAL; + } + status = nrf_wifi_fmac_set_listen_interval( + rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + params->listen_interval); + break; + case WIFI_PS_PARAM_TIMEOUT: + if ((vif_ctx_zep->if_type != NRF_WIFI_IFTYPE_STATION) +#ifdef CONFIG_NRF70_RAW_DATA_TX + && (vif_ctx_zep->if_type != NRF_WIFI_STA_TX_INJECTOR) +#endif /* CONFIG_NRF70_RAW_DATA_TX */ +#ifdef CONFIG_NRF70_PROMISC_DATA_RX + && (vif_ctx_zep->if_type != NRF_WIFI_STA_PROMISC_TX_INJECTOR) +#endif /* CONFIG_NRF70_PROMISC_DATA_RX */ + ) { + LOG_ERR("%s: Operation supported only in STA enabled mode", + __func__); + params->fail_reason = + WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL; + goto out; + } + + status = nrf_wifi_fmac_set_power_save_timeout( + rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + params->timeout_ms); + break; + case WIFI_PS_PARAM_MODE: + if (params->mode == WIFI_PS_MODE_WMM) { + uapsd_queue = UAPSD_Q_MAX; /* WMM mode */ + } + + status = nrf_wifi_fmac_set_uapsd_queue(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + uapsd_queue); + break; + case WIFI_PS_PARAM_STATE: + status = nrf_wifi_fmac_set_power_save(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + params->enabled); + break; + case WIFI_PS_PARAM_WAKEUP_MODE: + status = nrf_wifi_fmac_set_ps_wakeup_mode( + rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + params->wakeup_mode); + break; + default: + params->fail_reason = + WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL; + return -ENOTSUP; + } + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Confiuring PS param %d failed", + __func__, params->type); + params->fail_reason = + WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL; + goto out; + } + + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_get_power_save_config(const struct device *dev, + struct wifi_ps_config *ps_config) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + int ret = -1; + int count = 0; + + if (!dev || !ps_config) { + return ret; + } + + 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_type != NRF_WIFI_IFTYPE_STATION) +#ifdef CONFIG_NRF70_RAW_DATA_TX + && (vif_ctx_zep->if_type != NRF_WIFI_STA_TX_INJECTOR) +#endif /* CONFIG_NRF70_RAW_DATA_TX */ +#ifdef CONFIG_NRF70_PROMISC_DATA_RX + && (vif_ctx_zep->if_type != NRF_WIFI_STA_PROMISC_TX_INJECTOR) +#endif /* CONFIG_NRF70_PROMISC_DATA_RX */ + ) { + LOG_ERR("%s: Operation supported only in STA enabled mode", + __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 (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + goto out; + } + + vif_ctx_zep->ps_info = ps_config; + + vif_ctx_zep->ps_config_info_evnt = false; + + status = nrf_wifi_fmac_get_power_save_info(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_get_power_save_info failed", + __func__); + goto out; + } + + do { + nrf_wifi_osal_sleep_ms(1); + count++; + } while ((vif_ctx_zep->ps_config_info_evnt == false) && + (count < NRF_WIFI_FMAC_PS_CONF_EVNT_RECV_TIMEOUT)); + + if (count == NRF_WIFI_FMAC_PS_CONF_EVNT_RECV_TIMEOUT) { + nrf_wifi_osal_log_err("%s: Timed out", + __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +/* TWT interval conversion helpers: User <-> Protocol */ +static struct twt_interval_float nrf_wifi_twt_us_to_float(uint32_t twt_interval) +{ + double mantissa = 0.0; + int exponent = 0; + struct twt_interval_float twt_interval_fp; + + double twt_interval_ms = twt_interval / 1000.0; + + mantissa = frexp(twt_interval_ms, &exponent); + /* Ceiling and conversion to milli seconds */ + twt_interval_fp.mantissa = ceil(mantissa * 1000); + twt_interval_fp.exponent = exponent; + + return twt_interval_fp; +} + +static uint64_t nrf_wifi_twt_float_to_us(struct twt_interval_float twt_interval_fp) +{ + /* Conversion to micro-seconds */ + return floor(ldexp(twt_interval_fp.mantissa, twt_interval_fp.exponent) / (1000)) * + 1000; +} + +static unsigned char twt_wifi_mgmt_to_rpu_neg_type(enum wifi_twt_negotiation_type neg_type) +{ + unsigned char rpu_neg_type = 0; + + switch (neg_type) { + case WIFI_TWT_INDIVIDUAL: + rpu_neg_type = NRF_WIFI_TWT_NEGOTIATION_TYPE_INDIVIDUAL; + break; + case WIFI_TWT_BROADCAST: + rpu_neg_type = NRF_WIFI_TWT_NEGOTIATION_TYPE_BROADCAST; + break; + default: + LOG_ERR("%s: Invalid negotiation type: %d", + __func__, neg_type); + break; + } + + return rpu_neg_type; +} + +static enum wifi_twt_negotiation_type twt_rpu_to_wifi_mgmt_neg_type(unsigned char neg_type) +{ + enum wifi_twt_negotiation_type wifi_neg_type = WIFI_TWT_INDIVIDUAL; + + switch (neg_type) { + case NRF_WIFI_TWT_NEGOTIATION_TYPE_INDIVIDUAL: + wifi_neg_type = WIFI_TWT_INDIVIDUAL; + break; + case NRF_WIFI_TWT_NEGOTIATION_TYPE_BROADCAST: + wifi_neg_type = WIFI_TWT_BROADCAST; + break; + default: + LOG_ERR("%s: Invalid negotiation type: %d", + __func__, neg_type); + break; + } + + return wifi_neg_type; +} + +/* Though setup_cmd enums have 1-1 mapping but due to data type different need these */ +static enum wifi_twt_setup_cmd twt_rpu_to_wifi_mgmt_setup_cmd(signed int setup_cmd) +{ + enum wifi_twt_setup_cmd wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST; + + switch (setup_cmd) { + case NRF_WIFI_REQUEST_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST; + break; + case NRF_WIFI_SUGGEST_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_SUGGEST; + break; + case NRF_WIFI_DEMAND_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_DEMAND; + break; + case NRF_WIFI_GROUPING_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_GROUPING; + break; + case NRF_WIFI_ACCEPT_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_ACCEPT; + break; + case NRF_WIFI_ALTERNATE_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_ALTERNATE; + break; + case NRF_WIFI_DICTATE_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_DICTATE; + break; + case NRF_WIFI_REJECT_TWT: + wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REJECT; + break; + default: + LOG_ERR("%s: Invalid setup command: %d", + __func__, setup_cmd); + break; + } + + return wifi_setup_cmd; +} + +static signed int twt_wifi_mgmt_to_rpu_setup_cmd(enum wifi_twt_setup_cmd setup_cmd) +{ + signed int rpu_setup_cmd = NRF_WIFI_REQUEST_TWT; + + switch (setup_cmd) { + case WIFI_TWT_SETUP_CMD_REQUEST: + rpu_setup_cmd = NRF_WIFI_REQUEST_TWT; + break; + case WIFI_TWT_SETUP_CMD_SUGGEST: + rpu_setup_cmd = NRF_WIFI_SUGGEST_TWT; + break; + case WIFI_TWT_SETUP_CMD_DEMAND: + rpu_setup_cmd = NRF_WIFI_DEMAND_TWT; + break; + case WIFI_TWT_SETUP_CMD_GROUPING: + rpu_setup_cmd = NRF_WIFI_GROUPING_TWT; + break; + case WIFI_TWT_SETUP_CMD_ACCEPT: + rpu_setup_cmd = NRF_WIFI_ACCEPT_TWT; + break; + case WIFI_TWT_SETUP_CMD_ALTERNATE: + rpu_setup_cmd = NRF_WIFI_ALTERNATE_TWT; + break; + case WIFI_TWT_SETUP_CMD_DICTATE: + rpu_setup_cmd = NRF_WIFI_DICTATE_TWT; + break; + case WIFI_TWT_SETUP_CMD_REJECT: + rpu_setup_cmd = NRF_WIFI_REJECT_TWT; + break; + default: + LOG_ERR("%s: Invalid setup command: %d", + __func__, setup_cmd); + break; + } + + return rpu_setup_cmd; +} + +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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!vif_ctx || !ps_info) { + return; + } + + vif_ctx_zep = vif_ctx; + + vif_ctx_zep->ps_info->ps_params.mode = ps_info->ps_mode; + vif_ctx_zep->ps_info->ps_params.enabled = ps_info->enabled; + vif_ctx_zep->ps_info->num_twt_flows = ps_info->num_twt_flows; + vif_ctx_zep->ps_info->ps_params.timeout_ms = ps_info->ps_timeout; + vif_ctx_zep->ps_info->ps_params.listen_interval = ps_info->listen_interval; + vif_ctx_zep->ps_info->ps_params.wakeup_mode = ps_info->extended_ps; + + for (int i = 0; i < ps_info->num_twt_flows; i++) { + struct twt_interval_float twt_interval_fp; + struct wifi_twt_flow_info *twt_zep = &vif_ctx_zep->ps_info->twt_flows[i]; + struct nrf_wifi_umac_config_twt_info *twt_rpu = &ps_info->twt_flow_info[i]; + + memset(twt_zep, 0, sizeof(struct wifi_twt_flow_info)); + + twt_zep->flow_id = twt_rpu->twt_flow_id; + twt_zep->implicit = twt_rpu->is_implicit ? 1 : 0; + twt_zep->trigger = twt_rpu->ap_trigger_frame ? 1 : 0; + twt_zep->announce = twt_rpu->twt_flow_type == NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED; + twt_zep->negotiation_type = twt_rpu_to_wifi_mgmt_neg_type(twt_rpu->neg_type); + twt_zep->dialog_token = twt_rpu->dialog_token; + twt_interval_fp.mantissa = twt_rpu->twt_target_wake_interval_mantissa; + twt_interval_fp.exponent = twt_rpu->twt_target_wake_interval_exponent; + twt_zep->twt_interval = nrf_wifi_twt_float_to_us(twt_interval_fp); + twt_zep->twt_wake_interval = twt_rpu->nominal_min_twt_wake_duration; + } + + vif_ctx_zep->ps_config_info_evnt = true; +} + +static void nrf_wifi_twt_update_internal_state(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep, + bool setup, unsigned char flow_id) +{ + if (setup) { + vif_ctx_zep->twt_flows_map |= BIT(flow_id); + vif_ctx_zep->twt_flow_in_progress_map &= ~BIT(flow_id); + } else { + vif_ctx_zep->twt_flows_map &= ~BIT(flow_id); + } +} + +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) +{ + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_config_twt_info twt_info = {0}; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = 0; + struct wifi_twt_params twt_params = {0}; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __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; + } + + for (int flow_id = start_flow_id; flow_id < end_flow_id; flow_id++) { + if (!(vif_ctx_zep->twt_flows_map & BIT(flow_id))) { + continue; + } + twt_info.twt_flow_id = flow_id; + status = nrf_wifi_fmac_twt_teardown(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &twt_info); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: TWT teardown for flow id %d failed", + __func__, flow_id); + ret = -1; + continue; + } + /* UMAC doesn't send TWT teardown event for host initiated teardown */ + nrf_wifi_twt_update_internal_state(vif_ctx_zep, false, flow_id); + /* TODO: Remove this once UMAC sends the status */ + twt_params.operation = WIFI_TWT_TEARDOWN; + twt_params.flow_id = flow_id; + twt_params.teardown_status = WIFI_TWT_TEARDOWN_SUCCESS; + wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params); + } + +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_set_twt(const struct device *dev, + struct wifi_twt_params *twt_params) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_umac_config_twt_info twt_info = {0}; + int ret = -1; + + if (!dev || !twt_params) { + LOG_ERR("%s: dev or twt_params is NULL", __func__); + return ret; + } + + vif_ctx_zep = dev->data; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __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; + } + + if (!(twt_params->operation == WIFI_TWT_TEARDOWN && twt_params->teardown.teardown_all) && + twt_params->flow_id >= WIFI_MAX_TWT_FLOWS) { + LOG_ERR("%s: Invalid flow id: %d", + __func__, twt_params->flow_id); + twt_params->fail_reason = WIFI_TWT_FAIL_INVALID_FLOW_ID; + goto out; + } + + switch (twt_params->operation) { + case WIFI_TWT_SETUP: + if (vif_ctx_zep->twt_flow_in_progress_map & BIT(twt_params->flow_id)) { + twt_params->fail_reason = WIFI_TWT_FAIL_OPERATION_IN_PROGRESS; + goto out; + } + + if (twt_params->setup_cmd == WIFI_TWT_SETUP_CMD_REQUEST) { + if (vif_ctx_zep->twt_flows_map & BIT(twt_params->flow_id)) { + twt_params->fail_reason = WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS; + goto out; + } + } + + struct twt_interval_float twt_interval_fp = + nrf_wifi_twt_us_to_float(twt_params->setup.twt_interval); + + twt_info.twt_flow_id = twt_params->flow_id; + twt_info.neg_type = twt_wifi_mgmt_to_rpu_neg_type(twt_params->negotiation_type); + twt_info.setup_cmd = twt_wifi_mgmt_to_rpu_setup_cmd(twt_params->setup_cmd); + twt_info.ap_trigger_frame = twt_params->setup.trigger; + twt_info.is_implicit = twt_params->setup.implicit; + if (twt_params->setup.announce) { + twt_info.twt_flow_type = NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED; + } else { + twt_info.twt_flow_type = NRF_WIFI_TWT_FLOW_TYPE_UNANNOUNCED; + } + + twt_info.nominal_min_twt_wake_duration = + twt_params->setup.twt_wake_interval; + twt_info.twt_target_wake_interval_mantissa = twt_interval_fp.mantissa; + twt_info.twt_target_wake_interval_exponent = twt_interval_fp.exponent; + + twt_info.dialog_token = twt_params->dialog_token; + twt_info.twt_wake_ahead_duration = twt_params->setup.twt_wake_ahead_duration; + + status = nrf_wifi_fmac_twt_setup(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &twt_info); + + break; + case WIFI_TWT_TEARDOWN: + unsigned char start_flow_id = 0; + unsigned char end_flow_id = WIFI_MAX_TWT_FLOWS; + + if (!twt_params->teardown.teardown_all) { + if (!(vif_ctx_zep->twt_flows_map & BIT(twt_params->flow_id))) { + twt_params->fail_reason = WIFI_TWT_FAIL_INVALID_FLOW_ID; + goto out; + } + start_flow_id = twt_params->flow_id; + end_flow_id = twt_params->flow_id + 1; + twt_info.twt_flow_id = twt_params->flow_id; + } + + status = nrf_wifi_twt_teardown_flows(vif_ctx_zep, + start_flow_id, + end_flow_id); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: TWT teardown failed: start_flow_id: %d, end_flow_id: %d", + __func__, start_flow_id, end_flow_id); + goto out; + } + break; + + default: + LOG_ERR("Unknown TWT operation"); + status = NRF_WIFI_STATUS_FAIL; + break; + } + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Failed", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct wifi_twt_params twt_params; + struct twt_interval_float twt_interval_fp; + + if (!vif_ctx || !twt_setup_info) { + return; + } + + vif_ctx_zep = vif_ctx; + + twt_params.operation = WIFI_TWT_SETUP; + twt_params.flow_id = twt_setup_info->info.twt_flow_id; + twt_params.negotiation_type = twt_rpu_to_wifi_mgmt_neg_type(twt_setup_info->info.neg_type); + twt_params.setup_cmd = twt_rpu_to_wifi_mgmt_setup_cmd(twt_setup_info->info.setup_cmd); + twt_params.setup.trigger = twt_setup_info->info.ap_trigger_frame ? 1 : 0; + twt_params.setup.implicit = twt_setup_info->info.is_implicit ? 1 : 0; + twt_params.setup.announce = + twt_setup_info->info.twt_flow_type == NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED; + twt_params.setup.twt_wake_interval = + twt_setup_info->info.nominal_min_twt_wake_duration; + twt_interval_fp.mantissa = twt_setup_info->info.twt_target_wake_interval_mantissa; + twt_interval_fp.exponent = twt_setup_info->info.twt_target_wake_interval_exponent; + twt_params.setup.twt_interval = nrf_wifi_twt_float_to_us(twt_interval_fp); + twt_params.dialog_token = twt_setup_info->info.dialog_token; + twt_params.resp_status = twt_setup_info->info.twt_resp_status; + + if ((twt_setup_info->info.twt_resp_status == 0) || + (twt_setup_info->info.neg_type == NRF_WIFI_ACCEPT_TWT)) { + nrf_wifi_twt_update_internal_state(vif_ctx_zep, true, twt_params.flow_id); + } + + wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params); +} + + +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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct wifi_twt_params twt_params = {0}; + + if (!vif_ctx || !twt_teardown_info) { + return; + } + + vif_ctx_zep = vif_ctx; + + twt_params.operation = WIFI_TWT_TEARDOWN; + twt_params.flow_id = twt_teardown_info->info.twt_flow_id; + /* TODO: ADD reason code in the twt_params structure */ + nrf_wifi_twt_update_internal_state(vif_ctx_zep, false, twt_params.flow_id); + + wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params); +} + +void nrf_wifi_event_proc_twt_sleep_zep(void *vif_ctx, + struct nrf_wifi_umac_event_twt_sleep *sleep_evnt, + 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; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + struct nrf_wifi_fmac_priv_def *def_priv = NULL; +#ifdef CONFIG_NRF70_DATA_TX + int desc = 0; + int ac = 0; +#endif + 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; + } + + 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; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + def_priv = wifi_fmac_priv(fmac_dev_ctx->fpriv); + + if (!sleep_evnt) { + LOG_ERR("%s: sleep_evnt is NULL", __func__); + return; + } + + switch (sleep_evnt->info.type) { + case TWT_BLOCK_TX: + nrf_wifi_osal_spinlock_take(def_dev_ctx->tx_config.tx_lock); + + def_dev_ctx->twt_sleep_status = NRF_WIFI_FMAC_TWT_STATE_SLEEP; + + wifi_mgmt_raise_twt_sleep_state(vif_ctx_zep->zep_net_if_ctx, + WIFI_TWT_STATE_SLEEP); + nrf_wifi_osal_spinlock_rel(def_dev_ctx->tx_config.tx_lock); + break; + case TWT_UNBLOCK_TX: + nrf_wifi_osal_spinlock_take(def_dev_ctx->tx_config.tx_lock); + def_dev_ctx->twt_sleep_status = NRF_WIFI_FMAC_TWT_STATE_AWAKE; + wifi_mgmt_raise_twt_sleep_state(vif_ctx_zep->zep_net_if_ctx, + WIFI_TWT_STATE_AWAKE); +#ifdef CONFIG_NRF70_DATA_TX + for (ac = NRF_WIFI_FMAC_AC_BE; + ac <= NRF_WIFI_FMAC_AC_MAX; ++ac) { + desc = tx_desc_get(fmac_dev_ctx, ac); + if (desc < def_priv->num_tx_tokens) { + tx_pending_process(fmac_dev_ctx, desc, ac); + } + } +#endif + nrf_wifi_osal_spinlock_rel(def_dev_ctx->tx_config.tx_lock); + break; + default: + break; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +} + +#ifdef CONFIG_NRF70_SYSTEM_WITH_RAW_MODES +int nrf_wifi_mode(const struct device *dev, + struct wifi_mode_info *mode) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + int ret = -1; + + if (!dev || !mode) { + LOG_ERR("%s: illegal input parameters", __func__); + return ret; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __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; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + + if (!device_is_ready(dev)) { + LOG_ERR("%s: Device %s is not ready", + __func__, dev->name); + goto out; + } + + if (mode->oper == WIFI_MGMT_SET) { + status = nrf_wifi_check_mode_validity(mode->mode); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: mode setting is not valid", __func__); + goto out; + } + + if (vif_ctx_zep->authorized && (mode->mode == NRF_WIFI_MONITOR_MODE)) { + LOG_ERR("%s: Cannot set monitor mode when station is connected", + __func__); + goto out; + } + + /** + * Send the driver vif_idx instead of upper layer sent if_index. + * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep + * context maps the correct network interface index to current driver + * interface index. + */ + status = nrf_wifi_fmac_set_mode(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, mode->mode); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: mode set operation failed", __func__); + goto out; + } + + } else { + mode->mode = def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode; + /** + * This is a work-around to handle current UMAC mode handling. + * This might be removed in future versions when UMAC has more space. + */ +#ifdef CONFIG_NRF70_RAW_DATA_TX + if (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->txinjection_mode == true) { + mode->mode ^= NRF_WIFI_TX_INJECTION_MODE; + } +#endif /* CONFIG_NRF70_RAW_DATA_TX */ +#ifdef CONFIG_NRF70_PROMISC_DATA_RX + if (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->promisc_mode == true) { + mode->mode ^= NRF_WIFI_PROMISCUOUS_MODE; + } +#endif /* CONFIG_NRF70_PROMISC_DATA_RX */ + } + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} +#endif /* CONFIG_NRF70_SYSTEM_WITH_RAW_MODES */ + +#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) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + int ret = -1; + + if (!dev || !channel) { + LOG_ERR("%s: illegal input parameters", __func__); + return ret; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + return ret; + } + + if (vif_ctx_zep->authorized) { + LOG_ERR("%s: Cannot change channel when in station connected mode", __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; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + + if (channel->oper == WIFI_MGMT_SET) { + /** + * Send the driver vif_idx instead of upper layer sent if_index. + * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep + * context maps the correct network interface index to current driver + * interface index. + */ + status = nrf_wifi_fmac_set_channel(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + channel->channel); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: set channel failed", __func__); + goto out; + } + } else { + channel->channel = def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->channel; + } + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} +#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) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + int ret = -1; + + if (!dev || !filter) { + LOG_ERR("%s: Illegal input parameters", __func__); + goto out; + } + + vif_ctx_zep = dev->data; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL\n", __func__); + goto out; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + fmac_dev_ctx = rpu_ctx_zep->rpu_ctx; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + + if (filter->oper == WIFI_MGMT_SET) { + /** + * In case a user sets data + management + ctrl bits + * or all the filter bits. Map it to bit 0 set to + * enable "all" packet filter bit setting. + * In case only filter packet size is configured and filter + * setting is sent as zero, set the filter value to + * previously configured value. + */ + if (filter->filter == WIFI_MGMT_DATA_CTRL_FILTER_SETTING + || filter->filter == WIFI_ALL_FILTER_SETTING) { + filter->filter = 1; + } else if (filter->filter == 0) { + filter->filter = + def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter; + } + + /** + * Send the driver vif_idx instead of upper layer sent if_index. + * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep + * context maps the correct network interface index to current driver + * interface index + */ + status = nrf_wifi_fmac_set_packet_filter(rpu_ctx_zep->rpu_ctx, filter->filter, + vif_ctx_zep->vif_idx, filter->buffer_size); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Set filter operation failed\n", __func__); + goto out; + } + } else { + filter->filter = def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter; + } + ret = 0; +out: + return ret; +} +#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) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_umac_set_wiphy_info wiphy_info; + int ret = -1; + + if (!dev) { + LOG_ERR("%s: dev is NULL", __func__); + return ret; + } + + vif_ctx_zep = dev->data; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __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; + } + + + if (!rpu_ctx_zep->rpu_ctx) { + LOG_ERR("%s: RPU context not initialized", __func__); + return ret; + } + + if ((int)rts_threshold < -1) { + /* 0 or any positive value is passed to f/w. + * For RTS off, -1 is passed to f/w. + * All other negative values considered as invalid. + */ + LOG_ERR("%s: Invalid threshold value : %d", __func__, (int)rts_threshold); + return ret; + } + + memset(&wiphy_info, 0, sizeof(struct nrf_wifi_umac_set_wiphy_info)); + + wiphy_info.rts_threshold = (int)rts_threshold; + + k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + + status = nrf_wifi_fmac_set_wiphy_params(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &wiphy_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Configuring rts threshold failed\n", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + + return ret; +} diff --git a/drivers/wifi/nrfwifi/src/wifi_mgmt_scan.c b/drivers/wifi/nrfwifi/src/wifi_mgmt_scan.c new file mode 100644 index 000000000000..66cd72e4f58f --- /dev/null +++ b/drivers/wifi/nrfwifi/src/wifi_mgmt_scan.c @@ -0,0 +1,440 @@ +/* + * 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 + +#include +#include + +#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( + 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(nwb); + + if (frame_length > CONFIG_WIFI_MGMT_RAW_SCAN_RESULT_LENGTH) { + nrf_wifi_osal_mem_cpy(&bcn_prb_resp_info.data, + nrf_wifi_osal_nbuf_data_get(nwb), + CONFIG_WIFI_MGMT_RAW_SCAN_RESULT_LENGTH); + + } else { + nrf_wifi_osal_mem_cpy(&bcn_prb_resp_info.data, + nrf_wifi_osal_nbuf_data_get(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 */ diff --git a/drivers/wifi/nrfwifi/src/wifi_util.c b/drivers/wifi/nrfwifi/src/wifi_util.c new file mode 100644 index 000000000000..aec552754ab6 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/wifi_util.c @@ -0,0 +1,1005 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* @file + * @brief NRF Wi-Fi util shell module + */ +#include +#include "host_rpu_umac_if.h" +#include "fmac_api.h" +#include "fmac_util.h" +#include "fmac_main.h" +#include "wifi_util.h" + +extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep; +struct nrf_wifi_ctx_zep *ctx = &rpu_drv_priv_zep.rpu_ctx_zep; + +static bool check_valid_data_rate(const struct shell *sh, + unsigned char rate_flag, + unsigned int data_rate) +{ + bool ret = false; + + switch (rate_flag) { + case RPU_TPUT_MODE_LEGACY: + if ((data_rate == 1) || + (data_rate == 2) || + (data_rate == 55) || + (data_rate == 11) || + (data_rate == 6) || + (data_rate == 9) || + (data_rate == 12) || + (data_rate == 18) || + (data_rate == 24) || + (data_rate == 36) || + (data_rate == 48) || + (data_rate == 54)) { + ret = true; + } + break; + case RPU_TPUT_MODE_HT: + case RPU_TPUT_MODE_HE_SU: + case RPU_TPUT_MODE_VHT: + if ((data_rate >= 0) && (data_rate <= 7)) { + ret = true; + } + break; + case RPU_TPUT_MODE_HE_ER_SU: + if (data_rate >= 0 && data_rate <= 2) { + ret = true; + } + break; + default: + shell_fprintf(sh, + SHELL_ERROR, + "%s: Invalid rate_flag %d\n", + __func__, + rate_flag); + break; + } + + return ret; +} + + +int nrf_wifi_util_conf_init(struct rpu_conf_params *conf_params) +{ + if (!conf_params) { + return -ENOEXEC; + } + + memset(conf_params, 0, sizeof(*conf_params)); + + /* Initialize values which are other than 0 */ + conf_params->he_ltf = -1; + conf_params->he_gi = -1; + return 0; +} + + +static int nrf_wifi_util_set_he_ltf(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + char *ptr = NULL; + unsigned long he_ltf = 0; + + if (ctx->conf_params.set_he_ltf_gi) { + shell_fprintf(sh, + SHELL_ERROR, + "Disable 'set_he_ltf_gi', to set 'he_ltf'\n"); + return -ENOEXEC; + } + + he_ltf = strtoul(argv[1], &ptr, 10); + + if (he_ltf > 2) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid HE LTF value(%lu).\n", + he_ltf); + shell_help(sh); + return -ENOEXEC; + } + + ctx->conf_params.he_ltf = he_ltf; + + return 0; +} + + +static int nrf_wifi_util_set_he_gi(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + char *ptr = NULL; + unsigned long he_gi = 0; + + if (ctx->conf_params.set_he_ltf_gi) { + shell_fprintf(sh, + SHELL_ERROR, + "Disable 'set_he_ltf_gi', to set 'he_gi'\n"); + return -ENOEXEC; + } + + he_gi = strtoul(argv[1], &ptr, 10); + + if (he_gi > 2) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid HE GI value(%lu).\n", + he_gi); + shell_help(sh); + return -ENOEXEC; + } + + ctx->conf_params.he_gi = he_gi; + + return 0; +} + + +static int nrf_wifi_util_set_he_ltf_gi(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + char *ptr = NULL; + unsigned long val = 0; + + val = strtoul(argv[1], &ptr, 10); + + if ((val < 0) || (val > 1)) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid value(%lu).\n", + val); + shell_help(sh); + return -ENOEXEC; + } + + status = nrf_wifi_fmac_conf_ltf_gi(ctx->rpu_ctx, + ctx->conf_params.he_ltf, + ctx->conf_params.he_gi, + val); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + shell_fprintf(sh, + SHELL_ERROR, + "Programming ltf_gi failed\n"); + return -ENOEXEC; + } + + ctx->conf_params.set_he_ltf_gi = val; + + return 0; +} + +#ifdef CONFIG_NRF70_STA_MODE +static int nrf_wifi_util_set_uapsd_queue(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + char *ptr = NULL; + unsigned long val = 0; + + val = strtoul(argv[1], &ptr, 10); + + if ((val < UAPSD_Q_MIN) || (val > UAPSD_Q_MAX)) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid value(%lu).\n", + val); + shell_help(sh); + return -ENOEXEC; + } + + if (ctx->conf_params.uapsd_queue != val) { + status = nrf_wifi_fmac_set_uapsd_queue(ctx->rpu_ctx, + 0, + val); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + shell_fprintf(sh, + SHELL_ERROR, + "Programming uapsd_queue failed\n"); + return -ENOEXEC; + } + + ctx->conf_params.uapsd_queue = val; + } + + return 0; +} +#endif /* CONFIG_NRF70_STA_MODE */ + + +static int nrf_wifi_util_show_cfg(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + struct rpu_conf_params *conf_params = NULL; + + conf_params = &ctx->conf_params; + + shell_fprintf(sh, + SHELL_INFO, + "************* Configured Parameters ***********\n"); + shell_fprintf(sh, + SHELL_INFO, + "\n"); + + shell_fprintf(sh, + SHELL_INFO, + "he_ltf = %d\n", + conf_params->he_ltf); + + shell_fprintf(sh, + SHELL_INFO, + "he_gi = %u\n", + conf_params->he_gi); + + shell_fprintf(sh, + SHELL_INFO, + "set_he_ltf_gi = %d\n", + conf_params->set_he_ltf_gi); + + shell_fprintf(sh, + SHELL_INFO, + "uapsd_queue = %d\n", + conf_params->uapsd_queue); + + shell_fprintf(sh, + SHELL_INFO, + "rate_flag = %d, rate_val = %d\n", + ctx->conf_params.tx_pkt_tput_mode, + ctx->conf_params.tx_pkt_rate); + return 0; +} + +#ifdef CONFIG_NRF70_STA_MODE +static int nrf_wifi_util_tx_stats(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + int vif_index = -1; + int peer_index = 0; + int max_vif_index = MAX(MAX_NUM_APS, MAX_NUM_STAS); + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + void *queue = NULL; + unsigned int tx_pending_pkts = 0; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + + vif_index = atoi(argv[1]); + if ((vif_index < 0) || (vif_index >= max_vif_index)) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid vif index(%d).\n", + vif_index); + shell_help(sh); + return -ENOEXEC; + } + + fmac_dev_ctx = ctx->rpu_ctx; + def_dev_ctx = wifi_dev_priv(fmac_dev_ctx); + + /* TODO: Get peer_index from shell once AP mode is supported */ + shell_fprintf(sh, + SHELL_INFO, + "************* Tx Stats: vif(%d) peer(0) ***********\n", + vif_index); + + for (int i = 0; i < NRF_WIFI_FMAC_AC_MAX ; i++) { + queue = def_dev_ctx->tx_config.data_pending_txq[peer_index][i]; + tx_pending_pkts = nrf_wifi_utils_q_len(queue); + + shell_fprintf( + sh, + SHELL_INFO, + "Outstanding tokens: ac: %d -> %d (pending_q_len: %d)\n", + i, + def_dev_ctx->tx_config.outstanding_descs[i], + tx_pending_pkts); + } + + return 0; +} +#endif /* CONFIG_NRF70_STA_MODE */ + + +static int nrf_wifi_util_tx_rate(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + char *ptr = NULL; + long rate_flag = -1; + long data_rate = -1; + + rate_flag = strtol(argv[1], &ptr, 10); + + if (rate_flag >= RPU_TPUT_MODE_MAX) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid value %ld for rate_flags\n", + rate_flag); + shell_help(sh); + return -ENOEXEC; + } + + + if (rate_flag == RPU_TPUT_MODE_HE_TB) { + data_rate = -1; + } else { + if (argc < 3) { + shell_fprintf(sh, + SHELL_ERROR, + "rate_val needed for rate_flag = %ld\n", + rate_flag); + shell_help(sh); + return -ENOEXEC; + } + + data_rate = strtol(argv[2], &ptr, 10); + + if (!(check_valid_data_rate(sh, + rate_flag, + data_rate))) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid data_rate %ld for rate_flag %ld\n", + data_rate, + rate_flag); + return -ENOEXEC; + } + + } + + status = nrf_wifi_fmac_set_tx_rate(ctx->rpu_ctx, + rate_flag, + data_rate); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + shell_fprintf(sh, + SHELL_ERROR, + "Programming tx_rate failed\n"); + return -ENOEXEC; + } + + ctx->conf_params.tx_pkt_tput_mode = rate_flag; + ctx->conf_params.tx_pkt_rate = data_rate; + + return 0; +} + + +#ifdef CONFIG_NRF_WIFI_LOW_POWER +static int nrf_wifi_util_show_host_rpu_ps_ctrl_state(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int rpu_ps_state = -1; + + status = nrf_wifi_fmac_get_host_rpu_ps_ctrl_state(ctx->rpu_ctx, + &rpu_ps_state); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + shell_fprintf(sh, + SHELL_ERROR, + "Failed to get PS state\n"); + return -ENOEXEC; + } + + shell_fprintf(sh, + SHELL_INFO, + "RPU sleep status = %s\n", rpu_ps_state ? "AWAKE" : "SLEEP"); + return 0; +} +#endif /* CONFIG_NRF_WIFI_LOW_POWER */ + + +static int nrf_wifi_util_show_vers(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + unsigned int fw_ver; + + fmac_dev_ctx = ctx->rpu_ctx; + + shell_fprintf(sh, SHELL_INFO, "Driver version: %s\n", + NRF70_DRIVER_VERSION); + + status = nrf_wifi_fmac_ver_get(fmac_dev_ctx, &fw_ver); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + shell_fprintf(sh, + SHELL_INFO, + "Failed to get firmware version\n"); + return -ENOEXEC; + } + + shell_fprintf(sh, SHELL_INFO, + "Firmware version: %d.%d.%d.%d\n", + 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)); + + return status; +} + +#ifndef CONFIG_NRF70_RADIO_TEST +static int nrf_wifi_util_dump_rpu_stats(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + struct rpu_op_stats stats; + enum rpu_stats_type stats_type = RPU_STATS_TYPE_ALL; + + if (argc == 2) { + const char *type = argv[1]; + + if (!strcmp(type, "umac")) { + stats_type = RPU_STATS_TYPE_UMAC; + } else if (!strcmp(type, "lmac")) { + stats_type = RPU_STATS_TYPE_LMAC; + } else if (!strcmp(type, "phy")) { + stats_type = RPU_STATS_TYPE_PHY; + } else if (!strcmp(type, "all")) { + stats_type = RPU_STATS_TYPE_ALL; + } else { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid stats type %s\n", + type); + return -ENOEXEC; + } + } + + fmac_dev_ctx = ctx->rpu_ctx; + + memset(&stats, 0, sizeof(struct rpu_op_stats)); + status = nrf_wifi_fmac_stats_get(fmac_dev_ctx, 0, &stats); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + shell_fprintf(sh, + SHELL_ERROR, + "Failed to get stats\n"); + return -ENOEXEC; + } + + if (stats_type == RPU_STATS_TYPE_UMAC || stats_type == RPU_STATS_TYPE_ALL) { + struct rpu_umac_stats *umac = &stats.fw.umac; + + shell_fprintf(sh, SHELL_INFO, + "UMAC TX debug stats:\n" + "======================\n" + "tx_cmd: %u\n" + "tx_non_coalesce_pkts_rcvd_from_host: %u\n" + "tx_coalesce_pkts_rcvd_from_host: %u\n" + "tx_max_coalesce_pkts_rcvd_from_host: %u\n" + "tx_cmds_max_used: %u\n" + "tx_cmds_currently_in_use: %u\n" + "tx_done_events_send_to_host: %u\n" + "tx_done_success_pkts_to_host: %u\n" + "tx_done_failure_pkts_to_host: %u\n" + "tx_cmds_with_crypto_pkts_rcvd_from_host: %u\n" + "tx_cmds_with_non_crypto_pkts_rcvd_from_host: %u\n" + "tx_cmds_with_broadcast_pkts_rcvd_from_host: %u\n" + "tx_cmds_with_multicast_pkts_rcvd_from_host: %u\n" + "tx_cmds_with_unicast_pkts_rcvd_from_host: %u\n" + "xmit: %u\n" + "send_addba_req: %u\n" + "addba_resp: %u\n" + "softmac_tx: %u\n" + "internal_pkts: %u\n" + "external_pkts: %u\n" + "tx_cmds_to_lmac: %u\n" + "tx_dones_from_lmac: %u\n" + "total_cmds_to_lmac: %u\n" + "tx_packet_data_count: %u\n" + "tx_packet_mgmt_count: %u\n" + "tx_packet_beacon_count: %u\n" + "tx_packet_probe_req_count: %u\n" + "tx_packet_auth_count: %u\n" + "tx_packet_deauth_count: %u\n" + "tx_packet_assoc_req_count: %u\n" + "tx_packet_disassoc_count: %u\n" + "tx_packet_action_count: %u\n" + "tx_packet_other_mgmt_count: %u\n" + "tx_packet_non_mgmt_data_count: %u\n\n", + umac->tx_dbg_params.tx_cmd, + umac->tx_dbg_params.tx_non_coalesce_pkts_rcvd_from_host, + umac->tx_dbg_params.tx_coalesce_pkts_rcvd_from_host, + umac->tx_dbg_params.tx_max_coalesce_pkts_rcvd_from_host, + umac->tx_dbg_params.tx_cmds_max_used, + umac->tx_dbg_params.tx_cmds_currently_in_use, + umac->tx_dbg_params.tx_done_events_send_to_host, + umac->tx_dbg_params.tx_done_success_pkts_to_host, + umac->tx_dbg_params.tx_done_failure_pkts_to_host, + umac->tx_dbg_params.tx_cmds_with_crypto_pkts_rcvd_from_host, + umac->tx_dbg_params.tx_cmds_with_non_crypto_pkts_rcvd_from_host, + umac->tx_dbg_params.tx_cmds_with_broadcast_pkts_rcvd_from_host, + umac->tx_dbg_params.tx_cmds_with_multicast_pkts_rcvd_from_host, + umac->tx_dbg_params.tx_cmds_with_unicast_pkts_rcvd_from_host, + umac->tx_dbg_params.xmit, + umac->tx_dbg_params.send_addba_req, + umac->tx_dbg_params.addba_resp, + umac->tx_dbg_params.softmac_tx, + umac->tx_dbg_params.internal_pkts, + umac->tx_dbg_params.external_pkts, + umac->tx_dbg_params.tx_cmds_to_lmac, + umac->tx_dbg_params.tx_dones_from_lmac, + umac->tx_dbg_params.total_cmds_to_lmac, + umac->tx_dbg_params.tx_packet_data_count, + umac->tx_dbg_params.tx_packet_mgmt_count, + umac->tx_dbg_params.tx_packet_beacon_count, + umac->tx_dbg_params.tx_packet_probe_req_count, + umac->tx_dbg_params.tx_packet_auth_count, + umac->tx_dbg_params.tx_packet_deauth_count, + umac->tx_dbg_params.tx_packet_assoc_req_count, + umac->tx_dbg_params.tx_packet_disassoc_count, + umac->tx_dbg_params.tx_packet_action_count, + umac->tx_dbg_params.tx_packet_other_mgmt_count, + umac->tx_dbg_params.tx_packet_non_mgmt_data_count); + + shell_fprintf(sh, SHELL_INFO, + "UMAC RX debug stats\n" + "======================\n" + "lmac_events: %u\n" + "rx_events: %u\n" + "rx_coalesce_events: %u\n" + "total_rx_pkts_from_lmac: %u\n" + "max_refill_gap: %u\n" + "current_refill_gap: %u\n" + "out_of_order_mpdus: %u\n" + "reorder_free_mpdus: %u\n" + "umac_consumed_pkts: %u\n" + "host_consumed_pkts: %u\n" + "rx_mbox_post: %u\n" + "rx_mbox_receive: %u\n" + "reordering_ampdu: %u\n" + "timer_mbox_post: %u\n" + "timer_mbox_rcv: %u\n" + "work_mbox_post: %u\n" + "work_mbox_rcv: %u\n" + "tasklet_mbox_post: %u\n" + "tasklet_mbox_rcv: %u\n" + "userspace_offload_frames: %u\n" + "alloc_buf_fail: %u\n" + "rx_packet_total_count: %u\n" + "rx_packet_data_count: %u\n" + "rx_packet_qos_data_count: %u\n" + "rx_packet_protected_data_count: %u\n" + "rx_packet_mgmt_count: %u\n" + "rx_packet_beacon_count: %u\n" + "rx_packet_probe_resp_count: %u\n" + "rx_packet_auth_count: %u\n" + "rx_packet_deauth_count: %u\n" + "rx_packet_assoc_resp_count: %u\n" + "rx_packet_disassoc_count: %u\n" + "rx_packet_action_count: %u\n" + "rx_packet_probe_req_count: %u\n" + "rx_packet_other_mgmt_count: %u\n" + "max_coalesce_pkts: %d\n" + "null_skb_pointer_from_lmac: %u\n" + "unexpected_mgmt_pkt: %u\n\n", + umac->rx_dbg_params.lmac_events, + umac->rx_dbg_params.rx_events, + umac->rx_dbg_params.rx_coalesce_events, + umac->rx_dbg_params.total_rx_pkts_from_lmac, + umac->rx_dbg_params.max_refill_gap, + umac->rx_dbg_params.current_refill_gap, + umac->rx_dbg_params.out_of_order_mpdus, + umac->rx_dbg_params.reorder_free_mpdus, + umac->rx_dbg_params.umac_consumed_pkts, + umac->rx_dbg_params.host_consumed_pkts, + umac->rx_dbg_params.rx_mbox_post, + umac->rx_dbg_params.rx_mbox_receive, + umac->rx_dbg_params.reordering_ampdu, + umac->rx_dbg_params.timer_mbox_post, + umac->rx_dbg_params.timer_mbox_rcv, + umac->rx_dbg_params.work_mbox_post, + umac->rx_dbg_params.work_mbox_rcv, + umac->rx_dbg_params.tasklet_mbox_post, + umac->rx_dbg_params.tasklet_mbox_rcv, + umac->rx_dbg_params.userspace_offload_frames, + umac->rx_dbg_params.alloc_buf_fail, + umac->rx_dbg_params.rx_packet_total_count, + umac->rx_dbg_params.rx_packet_data_count, + umac->rx_dbg_params.rx_packet_qos_data_count, + umac->rx_dbg_params.rx_packet_protected_data_count, + umac->rx_dbg_params.rx_packet_mgmt_count, + umac->rx_dbg_params.rx_packet_beacon_count, + umac->rx_dbg_params.rx_packet_probe_resp_count, + umac->rx_dbg_params.rx_packet_auth_count, + umac->rx_dbg_params.rx_packet_deauth_count, + umac->rx_dbg_params.rx_packet_assoc_resp_count, + umac->rx_dbg_params.rx_packet_disassoc_count, + umac->rx_dbg_params.rx_packet_action_count, + umac->rx_dbg_params.rx_packet_probe_req_count, + umac->rx_dbg_params.rx_packet_other_mgmt_count, + umac->rx_dbg_params.max_coalesce_pkts, + umac->rx_dbg_params.null_skb_pointer_from_lmac, + umac->rx_dbg_params.unexpected_mgmt_pkt); + + shell_fprintf(sh, SHELL_INFO, + "UMAC control path stats\n" + "======================\n" + "cmd_init: %u\n" + "event_init_done: %u\n" + "cmd_rf_test: %u\n" + "cmd_connect: %u\n" + "cmd_get_stats: %u\n" + "event_ps_state: %u\n" + "cmd_set_reg: %u\n" + "cmd_get_reg: %u\n" + "cmd_req_set_reg: %u\n" + "cmd_trigger_scan: %u\n" + "event_scan_done: %u\n" + "cmd_get_scan: %u\n" + "umac_scan_req: %u\n" + "umac_scan_complete: %u\n" + "umac_scan_busy: %u\n" + "cmd_auth: %u\n" + "cmd_assoc: %u\n" + "cmd_deauth: %u\n" + "cmd_register_frame: %u\n" + "cmd_frame: %u\n" + "cmd_del_key: %u\n" + "cmd_new_key: %u\n" + "cmd_set_key: %u\n" + "cmd_get_key: %u\n" + "event_beacon_hint: %u\n" + "event_reg_change: %u\n" + "event_wiphy_reg_change: %u\n" + "cmd_set_station: %u\n" + "cmd_new_station: %u\n" + "cmd_del_station: %u\n" + "cmd_new_interface: %u\n" + "cmd_set_interface: %u\n" + "cmd_get_interface: %u\n" + "cmd_set_ifflags: %u\n" + "cmd_set_ifflags_done: %u\n" + "cmd_set_bss: %u\n" + "cmd_set_wiphy: %u\n" + "cmd_start_ap: %u\n" + "LMAC_CMD_PS: %u\n" + "CURR_STATE: %u\n\n", + umac->cmd_evnt_dbg_params.cmd_init, + umac->cmd_evnt_dbg_params.event_init_done, + umac->cmd_evnt_dbg_params.cmd_rf_test, + umac->cmd_evnt_dbg_params.cmd_connect, + umac->cmd_evnt_dbg_params.cmd_get_stats, + umac->cmd_evnt_dbg_params.event_ps_state, + umac->cmd_evnt_dbg_params.cmd_set_reg, + umac->cmd_evnt_dbg_params.cmd_get_reg, + umac->cmd_evnt_dbg_params.cmd_req_set_reg, + umac->cmd_evnt_dbg_params.cmd_trigger_scan, + umac->cmd_evnt_dbg_params.event_scan_done, + umac->cmd_evnt_dbg_params.cmd_get_scan, + umac->cmd_evnt_dbg_params.umac_scan_req, + umac->cmd_evnt_dbg_params.umac_scan_complete, + umac->cmd_evnt_dbg_params.umac_scan_busy, + umac->cmd_evnt_dbg_params.cmd_auth, + umac->cmd_evnt_dbg_params.cmd_assoc, + umac->cmd_evnt_dbg_params.cmd_deauth, + umac->cmd_evnt_dbg_params.cmd_register_frame, + umac->cmd_evnt_dbg_params.cmd_frame, + umac->cmd_evnt_dbg_params.cmd_del_key, + umac->cmd_evnt_dbg_params.cmd_new_key, + umac->cmd_evnt_dbg_params.cmd_set_key, + umac->cmd_evnt_dbg_params.cmd_get_key, + umac->cmd_evnt_dbg_params.event_beacon_hint, + umac->cmd_evnt_dbg_params.event_reg_change, + umac->cmd_evnt_dbg_params.event_wiphy_reg_change, + umac->cmd_evnt_dbg_params.cmd_set_station, + umac->cmd_evnt_dbg_params.cmd_new_station, + umac->cmd_evnt_dbg_params.cmd_del_station, + umac->cmd_evnt_dbg_params.cmd_new_interface, + umac->cmd_evnt_dbg_params.cmd_set_interface, + umac->cmd_evnt_dbg_params.cmd_get_interface, + umac->cmd_evnt_dbg_params.cmd_set_ifflags, + umac->cmd_evnt_dbg_params.cmd_set_ifflags_done, + umac->cmd_evnt_dbg_params.cmd_set_bss, + umac->cmd_evnt_dbg_params.cmd_set_wiphy, + umac->cmd_evnt_dbg_params.cmd_start_ap, + umac->cmd_evnt_dbg_params.LMAC_CMD_PS, + umac->cmd_evnt_dbg_params.CURR_STATE); + + shell_fprintf(sh, SHELL_INFO, + "UMAC interface stats\n" + "======================\n" + "tx_unicast_pkt_count: %u\n" + "tx_multicast_pkt_count: %u\n" + "tx_broadcast_pkt_count: %u\n" + "tx_bytes: %u\n" + "rx_unicast_pkt_count: %u\n" + "rx_multicast_pkt_count: %u\n" + "rx_broadcast_pkt_count: %u\n" + "rx_beacon_success_count: %u\n" + "rx_beacon_miss_count: %u\n" + "rx_bytes: %u\n" + "rx_checksum_error_count: %u\n\n" + "replay_attack_drop_cnt: %u\n\n", + umac->interface_data_stats.tx_unicast_pkt_count, + umac->interface_data_stats.tx_multicast_pkt_count, + umac->interface_data_stats.tx_broadcast_pkt_count, + umac->interface_data_stats.tx_bytes, + umac->interface_data_stats.rx_unicast_pkt_count, + umac->interface_data_stats.rx_multicast_pkt_count, + umac->interface_data_stats.rx_broadcast_pkt_count, + umac->interface_data_stats.rx_beacon_success_count, + umac->interface_data_stats.rx_beacon_miss_count, + umac->interface_data_stats.rx_bytes, + umac->interface_data_stats.rx_checksum_error_count, + umac->interface_data_stats.replay_attack_drop_cnt); + } + + if (stats_type == RPU_STATS_TYPE_LMAC || stats_type == RPU_STATS_TYPE_ALL) { + struct rpu_lmac_stats *lmac = &stats.fw.lmac; + + shell_fprintf(sh, SHELL_INFO, + "LMAC stats\n" + "======================\n" + "reset_cmd_cnt: %u\n" + "reset_complete_event_cnt: %u\n" + "unable_gen_event: %u\n" + "ch_prog_cmd_cnt: %u\n" + "channel_prog_done: %u\n" + "tx_pkt_cnt: %u\n" + "tx_pkt_done_cnt: %u\n" + "scan_pkt_cnt: %u\n" + "internal_pkt_cnt: %u\n" + "internal_pkt_done_cnt: %u\n" + "ack_resp_cnt: %u\n" + "tx_timeout: %u\n" + "deagg_isr: %u\n" + "deagg_inptr_desc_empty: %u\n" + "deagg_circular_buffer_full: %u\n" + "lmac_rxisr_cnt: %u\n" + "rx_decryptcnt: %u\n" + "process_decrypt_fail: %u\n" + "prepa_rx_event_fail: %u\n" + "rx_core_pool_full_cnt: %u\n" + "rx_mpdu_crc_success_cnt: %u\n" + "rx_mpdu_crc_fail_cnt: %u\n" + "rx_ofdm_crc_success_cnt: %u\n" + "rx_ofdm_crc_fail_cnt: %u\n" + "rxDSSSCrcSuccessCnt: %u\n" + "rxDSSSCrcFailCnt: %u\n" + "rx_crypto_start_cnt: %u\n" + "rx_crypto_done_cnt: %u\n" + "rx_event_buf_full: %u\n" + "rx_extram_buf_full: %u\n" + "scan_req: %u\n" + "scan_complete: %u\n" + "scan_abort_req: %u\n" + "scan_abort_complete: %u\n" + "internal_buf_pool_null: %u\n" + "rpu_hw_lockup_count: %u\n" + "rpu_hw_lockup_recovery_done: %u\n\n", + lmac->reset_cmd_cnt, + lmac->reset_complete_event_cnt, + lmac->unable_gen_event, + lmac->ch_prog_cmd_cnt, + lmac->channel_prog_done, + lmac->tx_pkt_cnt, + lmac->tx_pkt_done_cnt, + lmac->scan_pkt_cnt, + lmac->internal_pkt_cnt, + lmac->internal_pkt_done_cnt, + lmac->ack_resp_cnt, + lmac->tx_timeout, + lmac->deagg_isr, + lmac->deagg_inptr_desc_empty, + lmac->deagg_circular_buffer_full, + lmac->lmac_rxisr_cnt, + lmac->rx_decryptcnt, + lmac->process_decrypt_fail, + lmac->prepa_rx_event_fail, + lmac->rx_core_pool_full_cnt, + lmac->rx_mpdu_crc_success_cnt, + lmac->rx_mpdu_crc_fail_cnt, + lmac->rx_ofdm_crc_success_cnt, + lmac->rx_ofdm_crc_fail_cnt, + lmac->rxDSSSCrcSuccessCnt, + lmac->rxDSSSCrcFailCnt, + lmac->rx_crypto_start_cnt, + lmac->rx_crypto_done_cnt, + lmac->rx_event_buf_full, + lmac->rx_extram_buf_full, + lmac->scan_req, + lmac->scan_complete, + lmac->scan_abort_req, + lmac->scan_abort_complete, + lmac->internal_buf_pool_null, + lmac->rpu_hw_lockup_count, + lmac->rpu_hw_lockup_recovery_done); + } + + if (stats_type == RPU_STATS_TYPE_PHY || stats_type == RPU_STATS_TYPE_ALL) { + struct rpu_phy_stats *phy = &stats.fw.phy; + + shell_fprintf(sh, SHELL_INFO, + "PHY stats\n" + "======================\n" + "rssi_avg: %d\n" + "pdout_val: %u\n" + "ofdm_crc32_pass_cnt: %u\n" + "ofdm_crc32_fail_cnt: %u\n" + "dsss_crc32_pass_cnt: %u\n" + "dsss_crc32_fail_cnt: %u\n\n", + phy->rssi_avg, + phy->pdout_val, + phy->ofdm_crc32_pass_cnt, + phy->ofdm_crc32_fail_cnt, + phy->dsss_crc32_pass_cnt, + phy->dsss_crc32_fail_cnt); + } + + return 0; +} +#endif /* CONFIG_NRF70_RADIO_TEST */ + +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY +static int nrf_wifi_util_trigger_rpu_recovery(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + + if (!ctx || !ctx->rpu_ctx) { + shell_fprintf(sh, + SHELL_ERROR, + "RPU context not initialized\n"); + return -ENOEXEC; + } + + fmac_dev_ctx = ctx->rpu_ctx; + + status = nrf_wifi_fmac_rpu_recovery_callback(fmac_dev_ctx, NULL, 0); + if (status != NRF_WIFI_STATUS_SUCCESS) { + shell_fprintf(sh, + SHELL_ERROR, + "Failed to trigger RPU recovery\n"); + return -ENOEXEC; + } + + shell_fprintf(sh, + SHELL_INFO, + "RPU recovery triggered\n"); + + return 0; +} +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ + +SHELL_STATIC_SUBCMD_SET_CREATE( + nrf_wifi_util_subcmds, + SHELL_CMD_ARG(he_ltf, + NULL, + "0 - 1x HE LTF\n" + "1 - 2x HE LTF\n" + "2 - 4x HE LTF ", + nrf_wifi_util_set_he_ltf, + 2, + 0), + SHELL_CMD_ARG(he_gi, + NULL, + "0 - 0.8 us\n" + "1 - 1.6 us\n" + "2 - 3.2 us ", + nrf_wifi_util_set_he_gi, + 2, + 0), + SHELL_CMD_ARG(set_he_ltf_gi, + NULL, + "0 - Disable\n" + "1 - Enable", + nrf_wifi_util_set_he_ltf_gi, + 2, + 0), +#ifdef CONFIG_NRF70_STA_MODE + SHELL_CMD_ARG(uapsd_queue, + NULL, + " - 0 to 15", + nrf_wifi_util_set_uapsd_queue, + 2, + 0), +#endif /* CONFIG_NRF70_STA_MODE */ + SHELL_CMD_ARG(show_config, + NULL, + "Display the current configuration values", + nrf_wifi_util_show_cfg, + 1, + 0), +#ifdef CONFIG_NRF70_STA_MODE + SHELL_CMD_ARG(tx_stats, + NULL, + "Displays transmit statistics\n" + "vif_index: 0 - 1\n", + nrf_wifi_util_tx_stats, + 2, + 0), +#endif /* CONFIG_NRF70_STA_MODE */ + SHELL_CMD_ARG(tx_rate, + NULL, + "Sets TX data rate to either a fixed value or AUTO\n" + "Parameters:\n" + " : The TX data rate type to be set, where:\n" + " 0 - LEGACY\n" + " 1 - HT\n" + " 2 - VHT\n" + " 3 - HE_SU\n" + " 4 - HE_ER_SU\n" + " 5 - AUTO\n" + " : The TX data rate value to be set, valid values are:\n" + " Legacy : <1, 2, 55, 11, 6, 9, 12, 18, 24, 36, 48, 54>\n" + " Non-legacy: \n" + " AUTO: \n", + nrf_wifi_util_tx_rate, + 2, + 1), +#ifdef CONFIG_NRF_WIFI_LOW_POWER + SHELL_CMD_ARG(sleep_state, + NULL, + "Display current sleep status", + nrf_wifi_util_show_host_rpu_ps_ctrl_state, + 1, + 0), +#endif /* CONFIG_NRF_WIFI_LOW_POWER */ + SHELL_CMD_ARG(show_vers, + NULL, + "Display the driver and the firmware versions", + nrf_wifi_util_show_vers, + 1, + 0), +#ifndef CONFIG_NRF70_RADIO_TEST + SHELL_CMD_ARG(rpu_stats, + NULL, + "Display RPU stats " + "Parameters: umac or lmac or phy or all (default)", + nrf_wifi_util_dump_rpu_stats, + 1, + 1), +#endif /* CONFIG_NRF70_RADIO_TEST */ +#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY + SHELL_CMD_ARG(rpu_recovery_test, + NULL, + "Trigger RPU recovery", + nrf_wifi_util_trigger_rpu_recovery, + 1, + 0), +#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ + SHELL_SUBCMD_SET_END); + + +SHELL_CMD_REGISTER(wifi_util, + &nrf_wifi_util_subcmds, + "nRF Wi-Fi utility shell commands", + NULL); + + +static int nrf_wifi_util_init(void) +{ + + if (nrf_wifi_util_conf_init(&ctx->conf_params) < 0) + return -1; + + return 0; +} + + +SYS_INIT(nrf_wifi_util_init, + APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/drivers/wifi/nrfwifi/src/wifi_util.h b/drivers/wifi/nrfwifi/src/wifi_util.h new file mode 100644 index 000000000000..2ab188efed4b --- /dev/null +++ b/drivers/wifi/nrfwifi/src/wifi_util.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +struct nrf_wifi_ctx_zep_rt { + struct nrf_wifi_fmac_priv *fmac_priv; + struct rpu_conf_params conf_params; +}; diff --git a/drivers/wifi/nrfwifi/src/work.c b/drivers/wifi/nrfwifi/src/work.c new file mode 100644 index 000000000000..dbc716a6eeb8 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/work.c @@ -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 +#include +#include +#include + +#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); diff --git a/drivers/wifi/nrfwifi/src/work.h b/drivers/wifi/nrfwifi/src/work.h new file mode 100644 index 000000000000..57759fa5924e --- /dev/null +++ b/drivers/wifi/nrfwifi/src/work.h @@ -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__ */ diff --git a/drivers/wifi/nrfwifi/src/wpa_supp_if.c b/drivers/wifi/nrfwifi/src/wpa_supp_if.c new file mode 100644 index 000000000000..6abddfb9bea5 --- /dev/null +++ b/drivers/wifi/nrfwifi/src/wpa_supp_if.c @@ -0,0 +1,2761 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief File containing WPA supplicant interface specific definitions for the + * Zephyr OS layer of the Wi-Fi driver. + */ +#include + +#include +#include + +#include "fmac_main.h" +#include "fmac_util.h" +#include "wifi_mgmt.h" +#include "wpa_supp_if.h" + +LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL); + +K_SEM_DEFINE(wait_for_event_sem, 0, 1); +K_SEM_DEFINE(wait_for_scan_resp_sem, 0, 1); +static K_MUTEX_DEFINE(mgmt_tx_lock); + +#define ACTION_FRAME_RESP_TIMEOUT_MS 5000 +#define SET_IFACE_EVENT_TIMEOUT_MS 5000 +#define CARR_ON_TIMEOUT_MS 5000 + +static int get_nrf_wifi_auth_type(int wpa_auth_alg) +{ + if (wpa_auth_alg & WPA_AUTH_ALG_OPEN) { + return NRF_WIFI_AUTHTYPE_OPEN_SYSTEM; + } + if (wpa_auth_alg & WPA_AUTH_ALG_SHARED) { + return NRF_WIFI_AUTHTYPE_SHARED_KEY; + } + if (wpa_auth_alg & WPA_AUTH_ALG_LEAP) { + return NRF_WIFI_AUTHTYPE_NETWORK_EAP; + } + if (wpa_auth_alg & WPA_AUTH_ALG_FT) { + return NRF_WIFI_AUTHTYPE_FT; + } + if (wpa_auth_alg & WPA_AUTH_ALG_SAE) { + return NRF_WIFI_AUTHTYPE_SAE; + } + + return NRF_WIFI_AUTHTYPE_MAX; +} + +static unsigned int wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len) +{ + switch (alg) { + case WPA_ALG_WEP: + if (key_len == 5) { + return RSN_CIPHER_SUITE_WEP40; + } + return RSN_CIPHER_SUITE_WEP104; + case WPA_ALG_TKIP: + return RSN_CIPHER_SUITE_TKIP; + case WPA_ALG_CCMP: + return RSN_CIPHER_SUITE_CCMP; + case WPA_ALG_GCMP: + return RSN_CIPHER_SUITE_GCMP; + case WPA_ALG_CCMP_256: + return RSN_CIPHER_SUITE_CCMP_256; + case WPA_ALG_GCMP_256: + return RSN_CIPHER_SUITE_GCMP_256; + case WPA_ALG_BIP_CMAC_128: + return RSN_CIPHER_SUITE_AES_128_CMAC; + case WPA_ALG_BIP_GMAC_128: + return RSN_CIPHER_SUITE_BIP_GMAC_128; + case WPA_ALG_BIP_GMAC_256: + return RSN_CIPHER_SUITE_BIP_GMAC_256; + case WPA_ALG_BIP_CMAC_256: + return RSN_CIPHER_SUITE_BIP_CMAC_256; + case WPA_ALG_SMS4: + return RSN_CIPHER_SUITE_SMS4; + case WPA_ALG_KRK: + return RSN_CIPHER_SUITE_KRK; + case WPA_ALG_NONE: + LOG_ERR("%s: Unexpected encryption algorithm %d", __func__, alg); + return 0; + } + + LOG_ERR("%s: Unsupported encryption algorithm %d", __func__, alg); + return 0; +} + +static enum chan_width drv2supp_chan_width(int width) +{ + switch (width) { + case NRF_WIFI_CHAN_WIDTH_20_NOHT: + return CHAN_WIDTH_20_NOHT; + case NRF_WIFI_CHAN_WIDTH_20: + return CHAN_WIDTH_20; + case NRF_WIFI_CHAN_WIDTH_40: + return CHAN_WIDTH_40; + case NRF_WIFI_CHAN_WIDTH_80: + return CHAN_WIDTH_80; + case NRF_WIFI_CHAN_WIDTH_80P80: + return CHAN_WIDTH_80P80; + case NRF_WIFI_CHAN_WIDTH_160: + return CHAN_WIDTH_160; + default: + break; + } + return CHAN_WIDTH_UNKNOWN; +} + +void nrf_wifi_wpa_supp_event_proc_scan_start(void *if_priv) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + vif_ctx_zep = if_priv; + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.scan_start) { + vif_ctx_zep->supp_callbk_fns.scan_start(vif_ctx_zep->supp_drv_if_ctx); + } +} + +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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + union wpa_event_data event; + struct scan_info *info = NULL; + + vif_ctx_zep = if_priv; + + memset(&event, 0, sizeof(event)); + + info = &event.scan_info; + + info->aborted = aborted; + 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); + } + k_work_cancel_delayable(&vif_ctx_zep->scan_timeout_work); + vif_ctx_zep->scan_in_progress = false; + k_sem_give(&wait_for_scan_resp_sem); +} + +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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct wpa_scan_res *r = NULL; + const unsigned char *ie = NULL; + const unsigned char *beacon_ie = NULL; + unsigned int ie_len = 0; + unsigned int beacon_ie_len = 0; + unsigned char *pos = NULL; + + vif_ctx_zep = if_priv; + + if (scan_res->valid_fields & NRF_WIFI_EVENT_NEW_SCAN_RESULTS_IES_VALID) { + ie = scan_res->ies; + ie_len = scan_res->ies_len; + } + + if (scan_res->valid_fields & NRF_WIFI_EVENT_NEW_SCAN_RESULTS_BEACON_IES_VALID) { + beacon_ie = scan_res->ies + scan_res->ies_len; + beacon_ie_len = scan_res->beacon_ies_len; + } + + r = k_calloc(sizeof(*r) + ie_len + beacon_ie_len, sizeof(char)); + + if (!r) { + LOG_ERR("%s: Unable to allocate memory for scan result", __func__); + return; + } + + if (scan_res->valid_fields & NRF_WIFI_EVENT_NEW_SCAN_RESULTS_MAC_ADDR_VALID) { + memcpy(r->bssid, scan_res->mac_addr, ETH_ALEN); + } + + r->freq = scan_res->frequency; + + if (scan_res->valid_fields & NRF_WIFI_EVENT_NEW_SCAN_RESULTS_BEACON_INTERVAL_VALID) { + r->beacon_int = scan_res->beacon_interval; + } + + r->caps = scan_res->capability; + + r->flags |= WPA_SCAN_NOISE_INVALID; + + if (scan_res->signal.signal_type == NRF_WIFI_SIGNAL_TYPE_MBM) { + r->level = scan_res->signal.signal.mbm_signal; + r->level /= 100; /* mBm to dBm */ + r->flags |= (WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID); + } else if (scan_res->signal.signal_type == NRF_WIFI_SIGNAL_TYPE_UNSPEC) { + r->level = scan_res->signal.signal.unspec_signal; + r->flags |= WPA_SCAN_QUAL_INVALID; + } else { + r->flags |= (WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID); + } + + if (scan_res->valid_fields & NRF_WIFI_EVENT_NEW_SCAN_RESULTS_IES_TSF_VALID) { + r->tsf = scan_res->ies_tsf; + } + + if (scan_res->valid_fields & NRF_WIFI_EVENT_NEW_SCAN_RESULTS_BEACON_IES_TSF_VALID) { + if (scan_res->beacon_ies_tsf > r->tsf) { + r->tsf = scan_res->beacon_ies_tsf; + } + } + + if (scan_res->seen_ms_ago) { + r->age = scan_res->seen_ms_ago; + } + + r->ie_len = ie_len; + + pos = (unsigned char *)(r + 1); + + if (ie) { + memcpy(pos, ie, ie_len); + + pos += ie_len; + } + + r->beacon_ie_len = beacon_ie_len; + + if (beacon_ie) { + memcpy(pos, beacon_ie, beacon_ie_len); + } + + if (scan_res->valid_fields & NRF_WIFI_EVENT_NEW_SCAN_RESULTS_STATUS_VALID) { + switch (scan_res->status) { + case NRF_WIFI_BSS_STATUS_ASSOCIATED: + r->flags |= WPA_SCAN_ASSOCIATED; + break; + default: + break; + } + } + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.scan_res) { + vif_ctx_zep->supp_callbk_fns.scan_res(vif_ctx_zep->supp_drv_if_ctx, r, more_res); + } + + if (!more_res) { + vif_ctx_zep->scan_in_progress = false; + } + + k_free(r); +} + +void nrf_wifi_wpa_supp_event_proc_auth_resp(void *if_priv, + struct nrf_wifi_umac_event_mlme *auth_resp, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt = NULL; + const unsigned char *frame = NULL; + unsigned int frame_len = 0; + + vif_ctx_zep = if_priv; + + frame = auth_resp->frame.frame; + frame_len = auth_resp->frame.frame_len; + mgmt = (const struct ieee80211_mgmt *)frame; + + if (frame_len < 4 + (2 * NRF_WIFI_ETH_ADDR_LEN)) { + LOG_ERR("%s: MLME event too short", __func__); + return; + } + + + if (frame_len < 24 + sizeof(mgmt->u.auth)) { + LOG_ERR("%s: Authentication response frame too short", __func__); + return; + } + + memset(&event, 0, sizeof(event)); + + memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); + + event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); + + event.auth.auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); + + event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); + + if (frame_len > 24 + sizeof(mgmt->u.auth)) { + event.auth.ies = mgmt->u.auth.variable; + event.auth.ies_len = (frame_len - 24 - sizeof(mgmt->u.auth)); + } + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.auth_resp) { + vif_ctx_zep->supp_callbk_fns.auth_resp(vif_ctx_zep->supp_drv_if_ctx, &event); + } +} + +void nrf_wifi_wpa_supp_event_proc_assoc_resp(void *if_priv, + struct nrf_wifi_umac_event_mlme *assoc_resp, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt = NULL; + const unsigned char *frame = NULL; + unsigned int frame_len = 0; + unsigned short status = WLAN_STATUS_UNSPECIFIED_FAILURE; + + vif_ctx_zep = if_priv; + + frame = assoc_resp->frame.frame; + frame_len = assoc_resp->frame.frame_len; + mgmt = (const struct ieee80211_mgmt *)frame; + + if (frame_len < 24 + sizeof(mgmt->u.assoc_resp)) { + LOG_ERR("%s: Association response frame too short", __func__); + return; + } + + memset(&event, 0, sizeof(event)); + + status = le_to_host16(mgmt->u.assoc_resp.status_code); + + if (status != WLAN_STATUS_SUCCESS) { + event.assoc_reject.bssid = mgmt->bssid; + + if (frame_len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_reject.resp_ies = (unsigned char *)mgmt->u.assoc_resp.variable; + event.assoc_reject.resp_ies_len = + (frame_len - 24 - sizeof(mgmt->u.assoc_resp)); + } + + event.assoc_reject.status_code = status; + } else { + event.assoc_info.addr = mgmt->bssid; + event.assoc_info.resp_frame = frame; + event.assoc_info.resp_frame_len = frame_len; + event.assoc_info.freq = vif_ctx_zep->assoc_freq; + + if (frame_len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_info.resp_ies = (unsigned char *)mgmt->u.assoc_resp.variable; + event.assoc_info.resp_ies_len = + (frame_len - 24 - sizeof(mgmt->u.assoc_resp)); + } + + if (assoc_resp->req_ie_len > 0) { + event.assoc_info.req_ies = (unsigned char *)assoc_resp->req_ie; + event.assoc_info.req_ies_len = assoc_resp->req_ie_len; + } + + } + + if (vif_ctx_zep->supp_drv_if_ctx && + vif_ctx_zep->supp_callbk_fns.assoc_resp) { + vif_ctx_zep->supp_callbk_fns.assoc_resp(vif_ctx_zep->supp_drv_if_ctx, + &event, status); + } +} + +void nrf_wifi_wpa_supp_event_proc_deauth(void *if_priv, + struct nrf_wifi_umac_event_mlme *deauth, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt = NULL; + const unsigned char *frame = NULL; + unsigned int frame_len = 0; + + vif_ctx_zep = if_priv; + + frame = deauth->frame.frame; + frame_len = deauth->frame.frame_len; + mgmt = (const struct ieee80211_mgmt *)frame; + + if (frame_len < 24 + sizeof(mgmt->u.deauth)) { + LOG_ERR("%s: Deauthentication frame too short", __func__); + return; + } + + memset(&event, 0, sizeof(event)); + + event.deauth_info.addr = &mgmt->sa[0]; + event.deauth_info.reason_code = le_to_host16(mgmt->u.deauth.reason_code); + if (frame + frame_len > mgmt->u.deauth.variable) { + event.deauth_info.ie = mgmt->u.deauth.variable; + event.deauth_info.ie_len = (frame + frame_len - mgmt->u.deauth.variable); + } + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.deauth) { + vif_ctx_zep->supp_callbk_fns.deauth(vif_ctx_zep->supp_drv_if_ctx, + &event, mgmt); + } +} + +void nrf_wifi_wpa_supp_event_proc_disassoc(void *if_priv, + struct nrf_wifi_umac_event_mlme *disassoc, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt = NULL; + const unsigned char *frame = NULL; + unsigned int frame_len = 0; + + vif_ctx_zep = if_priv; + + frame = disassoc->frame.frame; + frame_len = disassoc->frame.frame_len; + mgmt = (const struct ieee80211_mgmt *)frame; + + if (frame_len < 24 + sizeof(mgmt->u.disassoc)) { + LOG_ERR("%s: Disassociation frame too short", __func__); + return; + } + + memset(&event, 0, sizeof(event)); + + event.disassoc_info.addr = &mgmt->sa[0]; + event.disassoc_info.reason_code = le_to_host16(mgmt->u.disassoc.reason_code); + if (frame + frame_len > mgmt->u.disassoc.variable) { + event.disassoc_info.ie = mgmt->u.disassoc.variable; + event.disassoc_info.ie_len = (frame + frame_len - mgmt->u.disassoc.variable); + } + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.disassoc) { + vif_ctx_zep->supp_callbk_fns.disassoc(vif_ctx_zep->supp_drv_if_ctx, &event); + } + + (void) nrf_wifi_twt_teardown_flows(vif_ctx_zep, 0, NRF_WIFI_MAX_TWT_FLOWS); +} + +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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + const struct device *device = DEVICE_DT_GET(DT_CHOSEN(zephyr_wifi)); + + if (!device) { + LOG_ERR("%s: Interface %s not found", __func__, iface_name); + return NULL; + } + + vif_ctx_zep = device->data; + + if (!vif_ctx_zep || !vif_ctx_zep->rpu_ctx_zep) { + LOG_ERR("%s: Interface %s not properly initialized", __func__, iface_name); + return NULL; + } + + /* Needed to make sure that during initialization, commands like setting regdomain + * does not access it. + */ + k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + vif_ctx_zep->supp_drv_if_ctx = supp_drv_if_ctx; + + memcpy(&vif_ctx_zep->supp_callbk_fns, supp_callbk_fns, + sizeof(vif_ctx_zep->supp_callbk_fns)); + + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return vif_ctx_zep; +} + +void nrf_wifi_wpa_supp_dev_deinit(void *if_priv) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + vif_ctx_zep = if_priv; + + vif_ctx_zep->supp_drv_if_ctx = NULL; +} + +int nrf_wifi_wpa_supp_scan2(void *if_priv, struct wpa_driver_scan_params *params) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_scan_info *scan_info = NULL; + int indx = 0; + int ret = -1; + int num_freqs = 0; + + if (!if_priv || !params) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep->rpu_ctx) { + LOG_ERR("%s: RPU context not initialized", __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; + } + + if (vif_ctx_zep->scan_in_progress) { + LOG_ERR("%s: Scan already in progress", __func__); + ret = -EBUSY; + goto out; + } + + if (params->freqs) { + for (indx = 0; params->freqs[indx]; indx++) + num_freqs++; + } + + scan_info = k_calloc(sizeof(*scan_info) + (num_freqs * sizeof(unsigned int)), + sizeof(char)); + + if (!scan_info) { + LOG_ERR("%s: Unable to allocate memory for scan info", __func__); + ret = -ENOMEM; + goto out; + } + + memset(scan_info, 0x0, sizeof(*scan_info)); + + if (params->freqs) { + for (indx = 0; params->freqs[indx]; indx++) { + scan_info->scan_params.center_frequency[indx] = + params->freqs[indx]; + } + scan_info->scan_params.num_scan_channels = indx; + } + + if (params->filter_ssids) { + scan_info->scan_params.num_scan_ssids = params->num_filter_ssids; + + for (indx = 0; indx < params->num_filter_ssids; indx++) { + memcpy(scan_info->scan_params.scan_ssids[indx].nrf_wifi_ssid, + params->filter_ssids[indx].ssid, + params->filter_ssids[indx].ssid_len); + + scan_info->scan_params.scan_ssids[indx].nrf_wifi_ssid_len = + params->filter_ssids[indx].ssid_len; + } + } + + scan_info->scan_reason = SCAN_CONNECT; + + /* Copy extra_ies */ + if (params->extra_ies_len && params->extra_ies_len <= NRF_WIFI_MAX_IE_LEN) { + memcpy(scan_info->scan_params.ie.ie, params->extra_ies, params->extra_ies_len); + scan_info->scan_params.ie.ie_len = params->extra_ies_len; + } else if (params->extra_ies_len) { + LOG_ERR("%s: extra_ies_len %d is greater than max IE len %d", + __func__, params->extra_ies_len, NRF_WIFI_MAX_IE_LEN); + goto out; + } + + 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: Scan trigger failed", __func__); + goto out; + } + + vif_ctx_zep->scan_type = SCAN_CONNECT; + 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; +} + +int nrf_wifi_wpa_supp_scan_abort(void *if_priv) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int sem_ret; + + vif_ctx_zep = if_priv; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + return -1; + } + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + + 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; + } + + if (!vif_ctx_zep->scan_in_progress) { + LOG_ERR("%s:Ignore scan abort, no scan in progress", __func__); + goto out; + } + + status = nrf_wifi_fmac_abort_scan(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_abort_scan failed", __func__); + goto out; + } + + k_sem_reset(&wait_for_scan_resp_sem); + sem_ret = k_sem_take(&wait_for_scan_resp_sem, K_MSEC(RPU_RESP_EVENT_TIMEOUT)); + if (sem_ret) { + LOG_ERR("%s: Timedout waiting for scan abort response, ret = %d", + __func__, sem_ret); + status = NRF_WIFI_STATUS_FAIL; + goto out; + } + +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return status; +} + +int nrf_wifi_wpa_supp_scan_results_get(void *if_priv) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret = -1; + + if (!if_priv) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + status = nrf_wifi_fmac_scan_res_get(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + SCAN_CONNECT); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_scan_res_get failed", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_deauthenticate(void *if_priv, const char *addr, unsigned short reason_code) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_disconn_info deauth_info; + int ret = -1; + + if ((!if_priv) || (!addr)) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + memset(&deauth_info, 0, sizeof(deauth_info)); + + deauth_info.reason_code = reason_code; + + memcpy(deauth_info.mac_addr, addr, sizeof(deauth_info.mac_addr)); + + status = nrf_wifi_fmac_deauth(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &deauth_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_deauth failed", __func__); + goto out; + } + + ret = nrf_wifi_twt_teardown_flows(vif_ctx_zep, 0, NRF_WIFI_MAX_TWT_FLOWS); +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_add_key(struct nrf_wifi_umac_key_info *key_info, enum wpa_alg alg, + int key_idx, + int defkey, const unsigned char *seq, size_t seq_len, + const unsigned char *key, size_t key_len) +{ + unsigned int suite = 0; + + suite = wpa_alg_to_cipher_suite(alg, key_len); + + if (!suite) { + return -1; + } + + if (defkey && alg == WPA_ALG_BIP_CMAC_128) { + key_info->nrf_wifi_flags = NRF_WIFI_KEY_DEFAULT_MGMT; + } else if (defkey) { + key_info->nrf_wifi_flags = NRF_WIFI_KEY_DEFAULT; + } + + key_info->key_idx = key_idx; + key_info->cipher_suite = suite; + + if (key && key_len) { + memcpy(key_info->key.nrf_wifi_key, key, key_len); + key_info->key.nrf_wifi_key_len = key_len; + } + if (seq && seq_len) { + memcpy(key_info->seq.nrf_wifi_seq, seq, seq_len); + key_info->seq.nrf_wifi_seq_len = seq_len; + } + + return 0; +} + +int nrf_wifi_wpa_supp_authenticate(void *if_priv, struct wpa_driver_auth_params *params, + struct wpa_bss *curr_bss) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_auth_info auth_info; + int ret = -1; + int type; + int count = 0; + int max_ie_len = 0; + + if ((!if_priv) || (!params)) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + +#ifdef CONFIG_NRF70_RAW_DATA_RX + if (vif_ctx_zep->if_type == NRF_WIFI_IFTYPE_MONITOR) { + LOG_ERR("%s: Interface is in Monitor mode - cannot connect to a BSS", __func__); + goto out; + } +#endif /* CONFIG_NRF70_RAW_DATA_RX */ + + memset(&auth_info, 0, sizeof(auth_info)); + + + if (params->bssid) { + memcpy(auth_info.nrf_wifi_bssid, params->bssid, ETH_ALEN); + } + + if (params->freq) { + auth_info.frequency = params->freq; + } + + if (params->ssid) { + memcpy(auth_info.ssid.nrf_wifi_ssid, params->ssid, params->ssid_len); + + auth_info.ssid.nrf_wifi_ssid_len = params->ssid_len; + } + + if (params->ie) { + max_ie_len = (params->ie_len > NRF_WIFI_MAX_IE_LEN) ? + NRF_WIFI_MAX_IE_LEN : params->ie_len; + memcpy(&auth_info.ie.ie, params->ie, max_ie_len); + auth_info.ie.ie_len = max_ie_len; + } else { + auth_info.scan_width = 0; /* hard coded */ + auth_info.nrf_wifi_signal = curr_bss->level; + auth_info.capability = curr_bss->caps; + auth_info.beacon_interval = curr_bss->beacon_int; + auth_info.tsf = curr_bss->tsf; + auth_info.from_beacon = 0; /* hard coded */ + } + + if (params->auth_data) { + auth_info.sae.sae_data_len = params->auth_data_len; + + memcpy(auth_info.sae.sae_data, params->auth_data, params->auth_data_len); + } + + type = get_nrf_wifi_auth_type(params->auth_alg); + + if (type != NRF_WIFI_AUTHTYPE_MAX) { + auth_info.auth_type = type; + } + + if (type == NRF_WIFI_AUTHTYPE_SHARED_KEY) { + size_t key_len = params->wep_key_len[params->wep_tx_keyidx]; + struct nrf_wifi_umac_key_info *key_info = &auth_info.key_info; + + key_info->cipher_suite = wpa_alg_to_cipher_suite(params->auth_alg, key_len); + memcpy(key_info->key.nrf_wifi_key, + params->wep_key[params->wep_tx_keyidx], + key_len); + key_info->key.nrf_wifi_key_len = key_len; + key_info->valid_fields |= NRF_WIFI_KEY_VALID | NRF_WIFI_KEY_IDX_VALID | + NRF_WIFI_CIPHER_SUITE_VALID; + } + + if (params->local_state_change) { + auth_info.nrf_wifi_flags |= NRF_WIFI_CMD_AUTHENTICATE_LOCAL_STATE_CHANGE; + } + + status = nrf_wifi_fmac_auth(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &auth_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: MLME command failed (auth): count=%d ret=%d", __func__, count, ret); + count++; + ret = -1; + } else { + LOG_DBG("%s:Authentication request sent successfully", __func__); + ret = 0; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_associate(void *if_priv, struct wpa_driver_associate_params *params) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_assoc_info assoc_info; + int ret = -1; + + if ((!if_priv) || (!params)) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: RPU context not initialized", __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; + } + + memset(&assoc_info, 0, sizeof(assoc_info)); + + if (params->bssid) { + memcpy(assoc_info.nrf_wifi_bssid, params->bssid, sizeof(assoc_info.nrf_wifi_bssid)); + } + + if (params->freq.freq) { + assoc_info.center_frequency = params->freq.freq; + vif_ctx_zep->assoc_freq = params->freq.freq; + } else { + vif_ctx_zep->assoc_freq = 0; + } + + if (params->prev_bssid) { + assoc_info.prev_bssid_flag = 1; + memcpy(assoc_info.prev_bssid, params->prev_bssid, ETH_ALEN); + } + + if (params->ssid) { + assoc_info.ssid.nrf_wifi_ssid_len = params->ssid_len; + + memcpy(assoc_info.ssid.nrf_wifi_ssid, params->ssid, params->ssid_len); + + } + + if (params->wpa_ie) { + assoc_info.wpa_ie.ie_len = params->wpa_ie_len; + memcpy(assoc_info.wpa_ie.ie, params->wpa_ie, params->wpa_ie_len); + } + + assoc_info.control_port = 1; + + if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) { + assoc_info.use_mfp = NRF_WIFI_MFP_REQUIRED; + } + + if (params->bss_max_idle_period) { + assoc_info.bss_max_idle_time = params->bss_max_idle_period; + } + + status = nrf_wifi_fmac_assoc(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &assoc_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: MLME command failed (assoc)", __func__); + } else { + LOG_DBG("%s: Association request sent successfully", __func__); + ret = 0; + } + +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +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) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_key_info key_info; + const unsigned char *mac_addr = NULL; + unsigned int suite; + int ret = -1; + + + if ((!if_priv) || (!ifname)) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep->rpu_ctx) { + 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; + } + + /* Can happen in a positive case where "net if down" is completed, but WPA + * supplicant is still deleting keys. + */ + if (!rpu_ctx_zep->rpu_ctx) { + goto out; + } + + memset(&key_info, 0, sizeof(key_info)); + + if (alg != WPA_ALG_NONE) { + suite = wpa_alg_to_cipher_suite(alg, key_len); + + if (!suite) { + goto out; + } + + memcpy(key_info.key.nrf_wifi_key, key, key_len); + + key_info.key.nrf_wifi_key_len = key_len; + key_info.cipher_suite = suite; + + key_info.valid_fields |= (NRF_WIFI_CIPHER_SUITE_VALID | NRF_WIFI_KEY_VALID); + } + + if (seq && seq_len) { + memcpy(key_info.seq.nrf_wifi_seq, seq, seq_len); + + key_info.seq.nrf_wifi_seq_len = seq_len; + key_info.valid_fields |= NRF_WIFI_SEQ_VALID; + } + + + /* TODO: Implement/check set_tx */ + if (addr && !is_broadcast_ether_addr(addr)) { + mac_addr = addr; + key_info.key_type = NRF_WIFI_KEYTYPE_PAIRWISE; + key_info.valid_fields |= NRF_WIFI_KEY_TYPE_VALID; + } else if (addr && is_broadcast_ether_addr(addr)) { + mac_addr = NULL; + key_info.key_type = NRF_WIFI_KEYTYPE_GROUP; + key_info.valid_fields |= NRF_WIFI_KEY_TYPE_VALID; + key_info.nrf_wifi_flags |= NRF_WIFI_KEY_DEFAULT_TYPE_MULTICAST; + } + + key_info.key_idx = key_idx; + key_info.valid_fields |= NRF_WIFI_KEY_IDX_VALID; + + if (alg == WPA_ALG_NONE) { + status = nrf_wifi_fmac_del_key(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + &key_info, mac_addr); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_del_key failed", __func__); + } else { + ret = 0; + } + } else { + status = nrf_wifi_fmac_add_key(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + &key_info, mac_addr); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_add_key failed", __func__); + } else { + ret = 0; + } + } + + /* + * If we failed or don't need to set the default TX key (below), + * we're done here. + */ + if (ret || !set_tx || alg == WPA_ALG_NONE) { + goto out; + } + + + memset(&key_info, 0, sizeof(key_info)); + + key_info.key_idx = key_idx; + key_info.valid_fields |= NRF_WIFI_KEY_IDX_VALID; + + if (alg == WPA_ALG_BIP_CMAC_128 || alg == WPA_ALG_BIP_GMAC_128 || + alg == WPA_ALG_BIP_GMAC_256 || alg == WPA_ALG_BIP_CMAC_256) { + key_info.nrf_wifi_flags = NRF_WIFI_KEY_DEFAULT_MGMT; + } else { + key_info.nrf_wifi_flags = NRF_WIFI_KEY_DEFAULT; + } + + if (addr && is_broadcast_ether_addr(addr)) { + key_info.nrf_wifi_flags |= NRF_WIFI_KEY_DEFAULT_TYPE_MULTICAST; + } else if (addr) { + key_info.nrf_wifi_flags |= NRF_WIFI_KEY_DEFAULT_TYPE_UNICAST; + } + + status = nrf_wifi_fmac_set_key(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &key_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_set_key failed", __func__); + ret = -1; + } else { + ret = 0; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_set_supp_port(void *if_priv, int authorized, char *bssid) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_umac_chg_sta_info chg_sta_info; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = -1; + + if (!if_priv || !bssid) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + if (vif_ctx_zep->if_op_state != NRF_WIFI_FMAC_IF_OP_STATE_UP) { + LOG_DBG("%s: Interface not UP, ignoring", __func__); + ret = 0; + goto out; + } + + memset(&chg_sta_info, 0x0, sizeof(chg_sta_info)); + + memcpy(chg_sta_info.mac_addr, bssid, ETH_ALEN); + + vif_ctx_zep->authorized = authorized; + + if (authorized) { + /* BIT(NL80211_STA_FLAG_AUTHORIZED) */ + chg_sta_info.sta_flags2.nrf_wifi_mask = 1 << 1; + /* BIT(NL80211_STA_FLAG_AUTHORIZED) */ + chg_sta_info.sta_flags2.nrf_wifi_set = 1 << 1; + } + + status = nrf_wifi_fmac_chg_sta(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &chg_sta_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_chg_sta failed", __func__); + ret = -1; + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_signal_poll(void *if_priv, struct wpa_signal_info *si, unsigned char *bssid) +{ + 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; + enum nrf_wifi_status ret = NRF_WIFI_STATUS_FAIL; + int sem_ret; + int rssi_record_elapsed_time_ms = 0; + + if (!if_priv || !si || !bssid) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + + vif_ctx_zep->signal_info = si; + + rssi_record_elapsed_time_ms = + nrf_wifi_osal_time_elapsed_us(vif_ctx_zep->rssi_record_timestamp_us) / 1000; + + if (rssi_record_elapsed_time_ms > CONFIG_NRF70_RSSI_STALE_TIMEOUT_MS) { + ret = nrf_wifi_fmac_get_station(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, bssid); + if (ret != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Failed to send get station info command", __func__); + goto out; + } + + sem_ret = k_sem_take(&wait_for_event_sem, K_MSEC(RPU_RESP_EVENT_TIMEOUT)); + if (sem_ret) { + LOG_ERR("%s: Failed to get station info, ret = %d", __func__, sem_ret); + ret = NRF_WIFI_STATUS_FAIL; + goto out; + } + } else { + si->current_signal = (int)vif_ctx_zep->rssi; + } + + ret = nrf_wifi_fmac_get_interface(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx); + if (ret != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Failed to send get interface info command", __func__); + goto out; + } + + sem_ret = k_sem_take(&wait_for_event_sem, K_MSEC(RPU_RESP_EVENT_TIMEOUT)); + if (sem_ret) { + LOG_ERR("%s: Failed to get interface info, ret = %d", __func__, sem_ret); + ret = NRF_WIFI_STATUS_FAIL; + goto out; + } + vif_ctx_zep->signal_info->frequency = vif_ctx_zep->assoc_freq; +out: + vif_ctx_zep->signal_info = NULL; + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +void nrf_wifi_wpa_supp_event_proc_get_sta(void *if_priv, + struct nrf_wifi_umac_event_new_station *info, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct wpa_signal_info *signal_info = NULL; + + if (!if_priv || !info) { + LOG_ERR("%s: Invalid params", __func__); + goto out; + } + + vif_ctx_zep = if_priv; + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + goto out; + } + +#ifdef CONFIG_NRF70_AP_MODE + vif_ctx_zep->inactive_time_sec = info->sta_info.inactive_time; +#endif /* CONFIG_NRF70_AP_MODE */ + + signal_info = vif_ctx_zep->signal_info; + /* Semaphore timedout */ + if (!signal_info) { + goto out; + } + + if (info->sta_info.valid_fields & NRF_WIFI_STA_INFO_SIGNAL_VALID) { + signal_info->current_signal = info->sta_info.signal; + } else { + signal_info->current_signal = -WPA_INVALID_NOISE; + } + + if (info->sta_info.valid_fields & NRF_WIFI_STA_INFO_SIGNAL_AVG_VALID) { + signal_info->avg_signal = info->sta_info.signal_avg; + } else { + signal_info->avg_signal = -WPA_INVALID_NOISE; + } + + if (info->sta_info.valid_fields & NRF_WIFI_STA_INFO_RX_BEACON_SIGNAL_AVG_VALID) { + signal_info->avg_beacon_signal = info->sta_info.rx_beacon_signal_avg; + } else { + signal_info->avg_beacon_signal = -WPA_INVALID_NOISE; + } + + signal_info->current_txrate = 0; + + if (info->sta_info.valid_fields & NRF_WIFI_STA_INFO_TX_BITRATE_VALID) { + if (info->sta_info.tx_bitrate.valid_fields & NRF_WIFI_RATE_INFO_BITRATE_VALID) { + signal_info->current_txrate = info->sta_info.tx_bitrate.bitrate * 100; + } + } +out: + k_sem_give(&wait_for_event_sem); +} + +void nrf_wifi_wpa_supp_event_proc_get_if(void *if_priv, + struct nrf_wifi_interface_info *info, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_chan_definition *chan_def_info = NULL; + struct wpa_signal_info *signal_info = NULL; + + if (!if_priv || !info) { + LOG_ERR("%s: Invalid params", __func__); + k_sem_give(&wait_for_event_sem); + return; + } + + vif_ctx_zep = if_priv; + signal_info = vif_ctx_zep->signal_info; + + /* Semaphore timedout */ + if (!signal_info) { + LOG_DBG("%s: Get interface Semaphore timedout", __func__); + return; + } + + chan_def_info = (struct nrf_wifi_chan_definition *)(&info->chan_def); + signal_info->chanwidth = drv2supp_chan_width(chan_def_info->width); + signal_info->center_frq1 = chan_def_info->center_frequency1; + signal_info->center_frq2 = chan_def_info->center_frequency2; + + k_sem_give(&wait_for_event_sem); +} + +void nrf_wifi_wpa_supp_event_mgmt_tx_status(void *if_priv, + struct nrf_wifi_umac_event_mlme *mlme_event, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + bool acked = false; + + if (!if_priv) { + LOG_ERR("%s: Missing interface context", __func__); + return; + } + + vif_ctx_zep = if_priv; + + if (!mlme_event) { + LOG_ERR("%s: Missing MLME event data", __func__); + return; + } + + acked = mlme_event->nrf_wifi_flags & NRF_WIFI_EVENT_MLME_ACK ? true : false; + LOG_DBG("%s: Mgmt frame %llx tx status: %s", + __func__, mlme_event->cookie, acked ? "ACK" : "NOACK"); + + if (vif_ctx_zep->supp_drv_if_ctx && + vif_ctx_zep->supp_callbk_fns.mgmt_tx_status) { + vif_ctx_zep->supp_callbk_fns.mgmt_tx_status(vif_ctx_zep->supp_drv_if_ctx, + mlme_event->frame.frame, + mlme_event->frame.frame_len, + acked); + } +} + +void nrf_wifi_wpa_supp_event_proc_unprot_mgmt(void *if_priv, + struct nrf_wifi_umac_event_mlme *unprot_mgmt, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt = NULL; + const unsigned char *frame = NULL; + unsigned int frame_len = 0; + int cmd_evnt = 0; + + vif_ctx_zep = if_priv; + + frame = unprot_mgmt->frame.frame; + frame_len = unprot_mgmt->frame.frame_len; + + mgmt = (const struct ieee80211_mgmt *)frame; + cmd_evnt = ((struct nrf_wifi_umac_hdr *)unprot_mgmt)->cmd_evnt; + + if (frame_len < 24 + sizeof(mgmt->u.deauth)) { + LOG_ERR("%s: Unprotected mgmt frame too short", __func__); + return; + } + + memset(&event, 0, sizeof(event)); + + event.unprot_deauth.sa = &mgmt->sa[0]; + event.unprot_deauth.da = &mgmt->da[0]; + + if (cmd_evnt == NRF_WIFI_UMAC_EVENT_UNPROT_DEAUTHENTICATE) { + event.unprot_deauth.reason_code = le_to_host16(mgmt->u.deauth.reason_code); + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.unprot_deauth) { + vif_ctx_zep->supp_callbk_fns.unprot_deauth(vif_ctx_zep->supp_drv_if_ctx, + &event); + } + } else if (cmd_evnt == NRF_WIFI_UMAC_EVENT_UNPROT_DISASSOCIATE) { + event.unprot_disassoc.reason_code = le_to_host16(mgmt->u.deauth.reason_code); + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.unprot_disassoc) { + vif_ctx_zep->supp_callbk_fns.unprot_disassoc(vif_ctx_zep->supp_drv_if_ctx, + &event); + } + } +} + +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) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_mgmt_tx_info *mgmt_tx_info = NULL; + unsigned int timeout = 0; + + if (!if_priv || !data) { + LOG_ERR("%s: Invalid params", __func__); + return -1; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + + 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; + } + + k_mutex_lock(&mgmt_tx_lock, K_FOREVER); + + mgmt_tx_info = k_calloc(sizeof(*mgmt_tx_info), sizeof(char)); + + if (!mgmt_tx_info) { + LOG_ERR("%s: Unable to allocate memory", __func__); + goto out; + } + + if (offchanok) + mgmt_tx_info->nrf_wifi_flags |= NRF_WIFI_CMD_FRAME_OFFCHANNEL_TX_OK; + + if (noack) + mgmt_tx_info->nrf_wifi_flags |= NRF_WIFI_CMD_FRAME_DONT_WAIT_FOR_ACK; + + if (no_cck) + mgmt_tx_info->nrf_wifi_flags |= NRF_WIFI_CMD_FRAME_TX_NO_CCK_RATE; + + if (freq) + mgmt_tx_info->frequency = freq; + + if (wait_time) + mgmt_tx_info->dur = wait_time; + + if (data_len) { + memcpy(mgmt_tx_info->frame.frame, data, data_len); + mgmt_tx_info->frame.frame_len = data_len; + } + + mgmt_tx_info->freq_params.frequency = freq; + mgmt_tx_info->freq_params.channel_width = NRF_WIFI_CHAN_WIDTH_20; + mgmt_tx_info->freq_params.center_frequency1 = freq; + mgmt_tx_info->freq_params.center_frequency2 = 0; + mgmt_tx_info->freq_params.channel_type = NRF_WIFI_CHAN_HT20; + + /* Going to RPU */ + mgmt_tx_info->host_cookie = cookie; + vif_ctx_zep->cookie_resp_received = false; + + LOG_DBG("%s: Sending frame to RPU: cookie=%d wait_time=%d no_ack=%d", __func__, + cookie, wait_time, noack); + status = nrf_wifi_fmac_mgmt_tx(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + mgmt_tx_info); + + if (status == NRF_WIFI_STATUS_FAIL) { + LOG_ERR("%s: nrf_wifi_fmac_mgmt_tx failed", __func__); + goto out; + } + + /* Both are needed as we use this to send_action where noack is hardcoded + * to 0 always. + */ + if (wait_time || !noack) { + if (!noack && !wait_time) { + wait_time = ACTION_FRAME_RESP_TIMEOUT_MS; + } + + while (!vif_ctx_zep->cookie_resp_received && + timeout++ < wait_time) { + k_sleep(K_MSEC(1)); + } + + if (!vif_ctx_zep->cookie_resp_received) { + LOG_ERR("%s: cookie response not received (%dms)", __func__, + timeout); + status = NRF_WIFI_STATUS_FAIL; + goto out; + } + status = NRF_WIFI_STATUS_SUCCESS; + } + +out: + if (mgmt_tx_info) + k_free(mgmt_tx_info); + k_mutex_unlock(&mgmt_tx_lock); + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return status; +} + +enum nrf_wifi_status nrf_wifi_parse_sband( + struct nrf_wifi_event_supported_band *event, + struct wpa_supp_event_supported_band *band + ) +{ + int count; + + if (event && (event->nrf_wifi_n_bitrates == 0 || event->nrf_wifi_n_channels == 0)) { + return NRF_WIFI_STATUS_FAIL; + } + memset(band, 0, sizeof(*band)); + + band->wpa_supp_n_channels = event->nrf_wifi_n_channels; + band->wpa_supp_n_bitrates = event->nrf_wifi_n_bitrates; + + for (count = 0; count < band->wpa_supp_n_channels; count++) { + struct wpa_supp_event_channel *chan = &band->channels[count]; + + if (count >= WPA_SUPP_SBAND_MAX_CHANNELS) { + LOG_ERR("%s: Failed to add channel", __func__); + break; + } + + chan->wpa_supp_flags = event->channels[count].nrf_wifi_flags; + chan->wpa_supp_max_power = event->channels[count].nrf_wifi_max_power; + chan->wpa_supp_time = event->channels[count].nrf_wifi_time; + chan->dfs_cac_msec = event->channels[count].dfs_cac_msec; + chan->ch_valid = event->channels[count].ch_valid; + chan->center_frequency = event->channels[count].center_frequency; + chan->dfs_state = event->channels[count].dfs_state; + } + + for (count = 0; count < band->wpa_supp_n_bitrates; count++) { + struct wpa_supp_event_rate *rate = &band->bitrates[count]; + + if (count >= WPA_SUPP_SBAND_MAX_RATES) { + LOG_ERR("%s: Failed to add bitrate", __func__); + break; + } + + rate->wpa_supp_flags = event->bitrates[count].nrf_wifi_flags; + rate->wpa_supp_bitrate = event->bitrates[count].nrf_wifi_bitrate; + } + + band->ht_cap.wpa_supp_ht_supported = event->ht_cap.nrf_wifi_ht_supported; + band->ht_cap.wpa_supp_cap = event->ht_cap.nrf_wifi_cap; + band->ht_cap.mcs.wpa_supp_rx_highest = event->ht_cap.mcs.nrf_wifi_rx_highest; + + for (count = 0; count < WPA_SUPP_HT_MCS_MASK_LEN; count++) { + band->ht_cap.mcs.wpa_supp_rx_mask[count] = + event->ht_cap.mcs.nrf_wifi_rx_mask[count]; + } + + band->ht_cap.mcs.wpa_supp_tx_params = event->ht_cap.mcs.nrf_wifi_tx_params; + + for (count = 0; count < NRF_WIFI_HT_MCS_RES_LEN; count++) { + + if (count >= WPA_SUPP_HT_MCS_RES_LEN) { + LOG_ERR("%s: Failed to add reserved bytes", __func__); + break; + } + + band->ht_cap.mcs.wpa_supp_reserved[count] = + event->ht_cap.mcs.nrf_wifi_reserved[count]; + } + + band->ht_cap.wpa_supp_ampdu_factor = event->ht_cap.nrf_wifi_ampdu_factor; + band->ht_cap.wpa_supp_ampdu_density = event->ht_cap.nrf_wifi_ampdu_density; + + band->vht_cap.wpa_supp_vht_supported = event->vht_cap.nrf_wifi_vht_supported; + band->vht_cap.wpa_supp_cap = event->vht_cap.nrf_wifi_cap; + + band->vht_cap.vht_mcs.rx_mcs_map = event->vht_cap.vht_mcs.rx_mcs_map; + band->vht_cap.vht_mcs.rx_highest = event->vht_cap.vht_mcs.rx_highest; + band->vht_cap.vht_mcs.tx_mcs_map = event->vht_cap.vht_mcs.tx_mcs_map; + band->vht_cap.vht_mcs.tx_highest = event->vht_cap.vht_mcs.tx_highest; + + band->band = event->band; + + return WLAN_STATUS_SUCCESS; +} + +void nrf_wifi_wpa_supp_event_get_wiphy(void *if_priv, + struct nrf_wifi_event_get_wiphy *wiphy_info, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct wpa_supp_event_supported_band band; + + if (!if_priv || !wiphy_info || !event_len) { + LOG_ERR("%s: Invalid parameters", __func__); + return; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + + memset(&band, 0, sizeof(band)); + + for (int i = 0; i < NRF_WIFI_EVENT_GET_WIPHY_NUM_BANDS; i++) { + if (nrf_wifi_parse_sband(&wiphy_info->sband[i], &band) != WLAN_STATUS_SUCCESS) { + continue; + } + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.get_wiphy_res) { + vif_ctx_zep->supp_callbk_fns.get_wiphy_res(vif_ctx_zep->supp_drv_if_ctx, + &band); + } + } + + if ((wiphy_info->params_valid & NRF_WIFI_GET_WIPHY_VALID_EXTENDED_CAPABILITIES) && + rpu_ctx_zep->extended_capa == NULL) { + + rpu_ctx_zep->extended_capa = k_malloc(wiphy_info->extended_capabilities_len); + + if (rpu_ctx_zep->extended_capa) { + memcpy(rpu_ctx_zep->extended_capa, wiphy_info->extended_capabilities, + wiphy_info->extended_capabilities_len); + } + + rpu_ctx_zep->extended_capa_mask = k_malloc(wiphy_info->extended_capabilities_len); + + if (rpu_ctx_zep->extended_capa_mask) { + memcpy(rpu_ctx_zep->extended_capa_mask, + wiphy_info->extended_capabilities_mask, + wiphy_info->extended_capabilities_len); + } else { + free(rpu_ctx_zep->extended_capa); + rpu_ctx_zep->extended_capa = NULL; + rpu_ctx_zep->extended_capa_len = 0; + } + } + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.get_wiphy_res) { + vif_ctx_zep->supp_callbk_fns.get_wiphy_res(vif_ctx_zep->supp_drv_if_ctx, NULL); + } +} + +int nrf_wifi_supp_get_wiphy(void *if_priv) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + + if (!if_priv) { + LOG_ERR("%s: Missing interface context", __func__); + return -1; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + + 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_get_wiphy(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_get_wiphy failed", __func__); + goto out; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return status; +} + +int nrf_wifi_supp_register_frame(void *if_priv, + u16 type, const u8 *match, size_t match_len, + bool multicast) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_mgmt_frame_info frame_info; + + if (!if_priv || !match || !match_len) { + LOG_ERR("%s: Invalid parameters", __func__); + return -1; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + + 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; + } + + memset(&frame_info, 0, sizeof(frame_info)); + + frame_info.frame_type = type; + frame_info.frame_match.frame_match_len = match_len; + memcpy(frame_info.frame_match.frame_match, match, match_len); + + status = nrf_wifi_fmac_register_frame(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + &frame_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_register_frame failed", __func__); + goto out; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return status; +} + +void nrf_wifi_wpa_supp_event_mgmt_rx_callbk_fn(void *if_priv, + struct nrf_wifi_umac_event_mlme *mlme_event, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!if_priv) { + LOG_ERR("%s: Missing interface context", __func__); + return; + } + + vif_ctx_zep = if_priv; + + if (!mlme_event || !event_len) { + LOG_ERR("%s: Missing MLME event data", __func__); + return; + } + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.mgmt_rx) { + vif_ctx_zep->supp_callbk_fns.mgmt_rx(vif_ctx_zep->supp_drv_if_ctx, + mlme_event->frame.frame, + mlme_event->frame.frame_len, + mlme_event->frequency, + mlme_event->rx_signal_dbm); + } +} + +int nrf_wifi_supp_get_capa(void *if_priv, struct wpa_driver_capa *capa) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_SUCCESS; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + + if (!if_priv || !capa) { + LOG_ERR("%s: Invalid parameters", __func__); + return -1; + } + + memset(capa, 0, sizeof(*capa)); + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + + 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; + } + + /* TODO: Get these from RPU*/ + /* Use SME */ + capa->flags = 0; + capa->flags |= WPA_DRIVER_FLAGS_SME; + capa->flags |= WPA_DRIVER_FLAGS_SAE; + capa->flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; + capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_RRM; + capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT; + if (IS_ENABLED(CONFIG_NRF70_AP_MODE)) { + capa->flags |= WPA_DRIVER_FLAGS_AP; + } + + capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40 | + WPA_DRIVER_CAPA_ENC_WEP104 | + WPA_DRIVER_CAPA_ENC_TKIP | + WPA_DRIVER_CAPA_ENC_CCMP | + WPA_DRIVER_CAPA_ENC_CCMP | + WPA_DRIVER_CAPA_ENC_CCMP_256 | + WPA_DRIVER_CAPA_ENC_GCMP_256; + + if (rpu_ctx_zep->extended_capa && rpu_ctx_zep->extended_capa_mask) { + capa->extended_capa = rpu_ctx_zep->extended_capa; + capa->extended_capa_mask = rpu_ctx_zep->extended_capa_mask; + capa->extended_capa_len = rpu_ctx_zep->extended_capa_len; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return status; +} + + +void nrf_wifi_wpa_supp_event_mac_chgd(void *if_priv) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!if_priv) { + LOG_ERR("%s: Invalid parameters", __func__); + return; + } + + vif_ctx_zep = if_priv; + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.mac_changed) { + vif_ctx_zep->supp_callbk_fns.mac_changed(vif_ctx_zep->supp_drv_if_ctx); + } + +} + + +int nrf_wifi_supp_get_conn_info(void *if_priv, struct wpa_conn_info *info) +{ + 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; + enum nrf_wifi_status ret = NRF_WIFI_STATUS_FAIL; + int sem_ret; + + if (!if_priv || !info) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + + vif_ctx_zep->conn_info = info; + ret = nrf_wifi_fmac_get_conn_info(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx); + if (ret != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_get_conn_info failed", __func__); + goto out; + } + + sem_ret = k_sem_take(&wait_for_event_sem, K_MSEC(RPU_RESP_EVENT_TIMEOUT)); + if (sem_ret) { + LOG_ERR("%s: Timeout: failed to get connection info, ret = %d", __func__, sem_ret); + ret = NRF_WIFI_STATUS_FAIL; + goto out; + } + +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + + +void nrf_wifi_supp_event_proc_get_conn_info(void *if_priv, + struct nrf_wifi_umac_event_conn_info *info, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct wpa_conn_info *conn_info = NULL; + + if (!if_priv || !info) { + LOG_ERR("%s: Invalid params", __func__); + k_sem_give(&wait_for_event_sem); + return; + } + vif_ctx_zep = if_priv; + conn_info = vif_ctx_zep->conn_info; + + conn_info->beacon_interval = info->beacon_interval; + conn_info->dtim_period = info->dtim_interval; + conn_info->twt_capable = info->twt_capable; + k_sem_give(&wait_for_event_sem); +} + +#ifdef CONFIG_NRF70_AP_MODE +static int nrf_wifi_vif_state_change(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep, + enum nrf_wifi_fmac_if_op_state state) +{ + struct nrf_wifi_umac_chg_vif_state_info vif_state_info = {0}; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + unsigned int timeout = 0; + struct nrf_wifi_fmac_vif_ctx *vif_ctx = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL; + int ret = -1; + + if (!vif_ctx_zep) { + LOG_ERR("%s: Invalid params", __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; + } + + def_dev_ctx = wifi_dev_priv(rpu_ctx_zep->rpu_ctx); + vif_ctx = def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]; + + vif_state_info.state = state; + vif_state_info.if_index = vif_ctx_zep->vif_idx; + vif_ctx->ifflags = false; + status = nrf_wifi_fmac_chg_vif_state(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &vif_state_info); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_chg_vif_state failed", + __func__); + goto out; + } + + while (!vif_ctx->ifflags && timeout++ < SET_IFACE_EVENT_TIMEOUT_MS) { + k_sleep(K_MSEC(1)); + } + + if (!vif_ctx->ifflags) { + LOG_ERR("%s: set interface state event not received (%dms)", __func__, timeout); + goto out; + } + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +static int nrf_wifi_iftype_change(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep, int iftype) +{ + struct nrf_wifi_umac_chg_vif_attr_info chg_vif_info = {0}; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret = -1; + unsigned int timeout = 0; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + + if (!vif_ctx_zep) { + LOG_ERR("%s: Invalid params", __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; + } + + ret = nrf_wifi_vif_state_change(vif_ctx_zep, NRF_WIFI_FMAC_IF_OP_STATE_DOWN); + if (ret) { + LOG_ERR("%s: Failed to set interface down", __func__); + goto out; + } + + chg_vif_info.iftype = iftype; + vif_ctx_zep->set_if_event_received = false; + vif_ctx_zep->set_if_status = 0; + status = nrf_wifi_fmac_chg_vif(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &chg_vif_info); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_chg_vif failed", __func__); + goto out; + } + + while (!vif_ctx_zep->set_if_event_received && + timeout++ < SET_IFACE_EVENT_TIMEOUT_MS) { + k_sleep(K_MSEC(1)); + } + + if (!vif_ctx_zep->set_if_event_received) { + LOG_ERR("%s: set interface event not received (%dms)", __func__, timeout); + goto out; + } + + if (vif_ctx_zep->set_if_status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: set interface failed: %d", __func__, vif_ctx_zep->set_if_status); + goto out; + } + + ret = nrf_wifi_vif_state_change(vif_ctx_zep, NRF_WIFI_FMAC_IF_OP_STATE_UP); + if (ret) { + LOG_ERR("%s: Failed to set interface up", __func__); + goto out; + } + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +static int nrf_wifi_wait_for_carrier_status(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep, + enum nrf_wifi_fmac_if_carr_state carrier_status) +{ + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret = -1; + unsigned int timeout = 0; + + if (!vif_ctx_zep) { + LOG_ERR("%s: Invalid params", __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; + } + + while (vif_ctx_zep->if_carr_state != carrier_status && + timeout++ < CARR_ON_TIMEOUT_MS) { + k_sleep(K_MSEC(1)); + } + + if (vif_ctx_zep->if_carr_state != carrier_status) { + LOG_ERR("%s: Carrier %s event not received in %dms", __func__, + carrier_status == NRF_WIFI_FMAC_IF_CARR_STATE_ON ? "ON" : "OFF", + timeout); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_init_ap(void *if_priv, struct wpa_driver_associate_params *params) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + + int ret = -1; + + if (!if_priv || !params) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + if (params->mode != IEEE80211_MODE_AP) { + LOG_ERR("%s: Invalid mode", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + ret = nrf_wifi_iftype_change(vif_ctx_zep, NRF_WIFI_IFTYPE_AP); + if (ret) { + LOG_ERR("%s: Failed to set interface type to AP: %d", __func__, ret); + goto out; + } + +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +static int wpas_cipher_to_nrf(int cipher) +{ + switch (cipher) { + case WPA_CIPHER_NONE: + return 0; + case WPA_CIPHER_WEP40: + return NRF_WIFI_FMAC_CIPHER_SUITE_WEP40; + case WPA_CIPHER_WEP104: + return NRF_WIFI_FMAC_CIPHER_SUITE_WEP104; + case WPA_CIPHER_TKIP: + return NRF_WIFI_FMAC_CIPHER_SUITE_TKIP; + case WPA_CIPHER_CCMP: + return NRF_WIFI_FMAC_CIPHER_SUITE_CCMP; + case WPA_CIPHER_CCMP_256: + return NRF_WIFI_FMAC_CIPHER_SUITE_CCMP_256; + default: + return -1; + } +} + +static int nrf_wifi_set_beacon_data(const struct wpa_driver_ap_params *params, + struct nrf_wifi_beacon_data *beacon_data) +{ + int ret = -1; + + if (params->head_len > ARRAY_SIZE(beacon_data->head)) { + LOG_ERR("%s: head_len too big", __func__); + goto out; + } + + if (params->tail_len > ARRAY_SIZE(beacon_data->tail)) { + LOG_ERR("%s: tail_len too big", __func__); + goto out; + } + + if (params->proberesp_len > ARRAY_SIZE(beacon_data->probe_resp)) { + LOG_ERR("%s: proberesp_len too big", __func__); + goto out; + } + + beacon_data->head_len = params->head_len; + beacon_data->tail_len = params->tail_len; + beacon_data->probe_resp_len = params->proberesp_len; + + if (params->head_len) { + memcpy(&beacon_data->head, params->head, + params->head_len); + } + + if (params->tail_len) { + memcpy(&beacon_data->tail, params->tail, + params->tail_len); + } + + if (params->proberesp_len) { + memcpy(&beacon_data->probe_resp, params->proberesp_ies, + params->proberesp_len); + } + + ret = 0; +out: + return ret; +} + +int nrf_wifi_supp_register_mgmt_frame(void *if_priv, + u16 frame_type, size_t match_len, const u8 *match) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_umac_mgmt_frame_info mgmt_frame_info = {0}; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = -1; + + if (!if_priv || (match_len && !match)) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + mgmt_frame_info.frame_type = frame_type; + mgmt_frame_info.frame_match.frame_match_len = match_len; + if (match_len >= NRF_WIFI_FRAME_MATCH_MAX_LEN) { + LOG_ERR("%s: match_len too big: %d (max %d)", __func__, match_len, + NRF_WIFI_FRAME_MATCH_MAX_LEN); + goto out; + } + memcpy(mgmt_frame_info.frame_match.frame_match, match, match_len); + + status = nrf_wifi_fmac_mgmt_frame_reg(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &mgmt_frame_info); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_mgmt_frame_reg failed", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +/* As per current design default is always STA */ +static int is_ap_dynamic_iface(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep) +{ + return (vif_ctx_zep->vif_idx != 0); +} + +static int nrf_wifi_set_bss(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep, + struct wpa_driver_ap_params *params) +{ + struct nrf_wifi_umac_bss_info bss_info = {0}; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret = -1; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int i; + + if (!vif_ctx_zep || !params) { + LOG_ERR("%s: Invalid params", __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; + } + + if (params->basic_rates) { + for (i = 0; params->basic_rates[i] != -1; i++) { + if (i >= ARRAY_SIZE(bss_info.basic_rates)) { + LOG_ERR("%s: basic_rates too big: %d (max %d)", __func__, i, + ARRAY_SIZE(bss_info.basic_rates)); + goto out; + } + bss_info.basic_rates[i] = params->basic_rates[i]; + } + bss_info.num_basic_rates = i; + } + bss_info.p2p_go_ctwindow = params->p2p_go_ctwindow; + bss_info.ht_opmode = params->ht_opmode; + bss_info.nrf_wifi_cts = params->cts_protect; + bss_info.preamble = params->preamble; + bss_info.nrf_wifi_slot = params->short_slot_time; + bss_info.ap_isolate = params->isolate; + + status = nrf_wifi_fmac_set_bss(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &bss_info); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_set_bss failed", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + + +static enum nrf_wifi_chan_width wpa_supp_chan_width_to_nrf(enum hostapd_hw_mode mode, + int bandwidth, int cfreq1, int cfreq2) +{ + switch (bandwidth) { + case 20: + if (mode == HOSTAPD_MODE_IEEE80211B) { + return NRF_WIFI_CHAN_WIDTH_20_NOHT; + } else { + return NRF_WIFI_CHAN_WIDTH_20; + }; + case 40: + return NRF_WIFI_CHAN_WIDTH_40; + case 80: + if (cfreq2) { + return NRF_WIFI_CHAN_WIDTH_80P80; + } else { + return NRF_WIFI_CHAN_WIDTH_80; + } + case 160: + return NRF_WIFI_CHAN_WIDTH_160; + }; + + return NRF_WIFI_CHAN_WIDTH_20; +} + +int nrf_wifi_wpa_supp_start_ap(void *if_priv, struct wpa_driver_ap_params *params) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret = -1; + struct nrf_wifi_umac_start_ap_info start_ap_info = {0}; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ch_width = 0; + + if (!if_priv || !params) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + nrf_wifi_set_beacon_data(params, &start_ap_info.beacon_data); + start_ap_info.beacon_interval = params->beacon_int; + start_ap_info.dtim_period = params->dtim_period; + start_ap_info.ssid.nrf_wifi_ssid_len = params->ssid_len; + memcpy(start_ap_info.ssid.nrf_wifi_ssid, params->ssid, params->ssid_len); + for (int i = 0; i < 32; i++) { + if ((params->pairwise_ciphers & BIT(i)) && + start_ap_info.connect_common_info.num_cipher_suites_pairwise < 7) { + if (wpas_cipher_to_nrf(i) < 0) { + LOG_DBG("%s: Unsupported cipher %d ignored", __func__, i); + continue; + } + start_ap_info.connect_common_info.cipher_suites_pairwise[i] = + wpas_cipher_to_nrf(i); + start_ap_info.connect_common_info.num_cipher_suites_pairwise++; + } + } + + ch_width = wpa_supp_chan_width_to_nrf(params->freq->mode, params->freq->bandwidth, + params->freq->center_freq1, params->freq->center_freq2); + + start_ap_info.freq_params.frequency = params->freq->freq; + start_ap_info.freq_params.channel_width = ch_width; + start_ap_info.freq_params.center_frequency1 = params->freq->center_freq1; + start_ap_info.freq_params.center_frequency2 = params->freq->center_freq2; + start_ap_info.freq_params.channel_type = params->freq->ht_enabled ? NRF_WIFI_CHAN_HT20 : + NRF_WIFI_CHAN_NO_HT; + start_ap_info.freq_params.valid_fields = NRF_WIFI_SET_FREQ_PARAMS_FREQ_VALID | + NRF_WIFI_SET_FREQ_PARAMS_CHANNEL_WIDTH_VALID | + NRF_WIFI_SET_FREQ_PARAMS_CENTER_FREQ1_VALID | + NRF_WIFI_SET_FREQ_PARAMS_CENTER_FREQ2_VALID | + NRF_WIFI_SET_FREQ_PARAMS_CHANNEL_TYPE_VALID; + + vif_ctx_zep->if_carr_state = NRF_WIFI_FMAC_IF_CARR_STATE_OFF; + status = nrf_wifi_fmac_start_ap(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &start_ap_info); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_start_ap failed", __func__); + goto out; + } + + ret = nrf_wifi_wait_for_carrier_status(vif_ctx_zep, NRF_WIFI_FMAC_IF_CARR_STATE_ON); + if (ret) { + goto out; + } + + ret = nrf_wifi_set_bss(vif_ctx_zep, params); + if (ret) { + LOG_ERR("%s: Failed to set BSS", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_change_beacon(void *if_priv, struct wpa_driver_ap_params *params) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + int ret = -1; + struct nrf_wifi_umac_set_beacon_info chg_bcn_info = {0}; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + + if (!if_priv || !params) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + nrf_wifi_set_beacon_data(params, &chg_bcn_info.beacon_data); + + status = nrf_wifi_fmac_chg_bcn(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &chg_bcn_info); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_chg_bcn failed", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_stop_ap(void *if_priv) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = -1; + + if (!if_priv) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + status = nrf_wifi_fmac_stop_ap(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx); + + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_stop_ap failed", __func__); + goto out; + } + + ret = nrf_wifi_wait_for_carrier_status(vif_ctx_zep, NRF_WIFI_FMAC_IF_CARR_STATE_OFF); + if (ret) { + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_deinit_ap(void *if_priv) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = -1; + + if (!if_priv) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_DBG("%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; + } + + status = nrf_wifi_wpa_supp_stop_ap(if_priv); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: Failed to stop AP", __func__); + goto out; + } + + if (!is_ap_dynamic_iface(vif_ctx_zep)) { + ret = nrf_wifi_iftype_change(vif_ctx_zep, NRF_WIFI_IFTYPE_STATION); + if (ret) { + LOG_ERR("%s: Failed to set interface type to STATION: %d", __func__, ret); + goto out; + } + } + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_sta_flags_to_nrf(int wpas_sta_flags) +{ + int nrf_sta_flags = 0; + + if (wpas_sta_flags & WPA_STA_AUTHORIZED) { + nrf_sta_flags |= NRF_WIFI_STA_FLAG_AUTHORIZED; + } + if (wpas_sta_flags & WPA_STA_WMM) { + nrf_sta_flags |= NRF_WIFI_STA_FLAG_WME; + } + if (wpas_sta_flags & WPA_STA_SHORT_PREAMBLE) { + nrf_sta_flags |= NRF_WIFI_STA_FLAG_SHORT_PREAMBLE; + } + if (wpas_sta_flags & WPA_STA_MFP) { + nrf_sta_flags |= NRF_WIFI_STA_FLAG_MFP; + } + if (wpas_sta_flags & WPA_STA_TDLS_PEER) { + nrf_sta_flags |= NRF_WIFI_STA_FLAG_TDLS_PEER; + } + /* Note: Do not set flags > NRF_WIFI_STA_FLAG_TDLS_PEER, else + * nrf_wifi_fmac_chg_sta will fail. This is equivalent to not + * setting WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE flag. + */ + + return nrf_sta_flags; +} + +int nrf_wifi_wpa_supp_sta_add(void *if_priv, struct hostapd_sta_add_params *params) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + struct nrf_wifi_umac_add_sta_info sta_info = {0}; + int ret = -1; + int i; + + if (!if_priv || !params) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + 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; + } + + sta_info.nrf_wifi_listen_interval = params->listen_interval; + sta_info.aid = params->aid; + sta_info.sta_capability = params->capability; + sta_info.supp_rates.nrf_wifi_num_rates = params->supp_rates_len; + /* TODO: sta_info.supp_rates.band */ + for (i = 0; i < params->supp_rates_len; i++) { + sta_info.supp_rates.rates[i] = params->supp_rates[i] & 0x7f; + } + + sta_info.ext_capability.ext_capability_len = params->ext_capab_len; + if (params->ext_capab_len >= NRF_WIFI_EXT_CAPABILITY_MAX_LEN) { + LOG_ERR("%s: ext_capab_len too big: %d (max %d)", __func__, + params->ext_capab_len, NRF_WIFI_EXT_CAPABILITY_MAX_LEN); + goto out; + } + memcpy(sta_info.ext_capability.ext_capability, params->ext_capab, + params->ext_capab_len); + + sta_info.supported_channels.supported_channels_len = params->supp_channels_len; + if (params->supp_channels_len >= NRF_WIFI_SUPPORTED_CHANNELS_MAX_LEN) { + LOG_ERR("%s: supp_channels_len too big: %d (max %d)", __func__, + params->supp_channels_len, NRF_WIFI_SUPPORTED_CHANNELS_MAX_LEN); + goto out; + } + memcpy(sta_info.supported_channels.supported_channels, params->supp_channels, + params->supp_channels_len); + + sta_info.supported_oper_classes.supported_oper_classes_len = params->supp_oper_classes_len; + if (params->supp_oper_classes_len >= NRF_WIFI_OPER_CLASSES_MAX_LEN) { + LOG_ERR("%s: supp_oper_classes_len too big: %d (max %d)", __func__, + params->supp_oper_classes_len, NRF_WIFI_OPER_CLASSES_MAX_LEN); + goto out; + } + memcpy(sta_info.supported_oper_classes.supported_oper_classes, params->supp_oper_classes, + params->supp_oper_classes_len); + + sta_info.sta_flags2.nrf_wifi_set = nrf_wifi_sta_flags_to_nrf(params->flags); + sta_info.sta_flags2.nrf_wifi_mask = sta_info.sta_flags2.nrf_wifi_set | + nrf_wifi_sta_flags_to_nrf(params->flags_mask); + + if (params->ht_capabilities) { + memcpy(sta_info.ht_capability, + params->ht_capabilities, + sizeof(sta_info.ht_capability)); + } + + if (params->vht_capabilities) { + memcpy(sta_info.vht_capability, + params->vht_capabilities, + sizeof(sta_info.vht_capability)); + } + + memcpy(sta_info.mac_addr, params->addr, sizeof(sta_info.mac_addr)); + + LOG_DBG("%s: %x, %x", __func__, + sta_info.sta_flags2.nrf_wifi_set, sta_info.sta_flags2.nrf_wifi_mask); + + if (params->set) { + status = nrf_wifi_fmac_chg_sta(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + (struct nrf_wifi_umac_chg_sta_info *)&sta_info); + } else { + status = nrf_wifi_fmac_add_sta(rpu_ctx_zep->rpu_ctx, + vif_ctx_zep->vif_idx, + &sta_info); + } + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_add_sta failed", __func__); + goto out; + } + + ret = 0; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_sta_remove(void *if_priv, const u8 *addr) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_umac_del_sta_info del_sta = {0}; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = -1; + + if (!if_priv || !addr) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_DBG("%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; + } + + memcpy(del_sta.mac_addr, addr, sizeof(del_sta.mac_addr)); + + status = nrf_wifi_fmac_del_sta(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &del_sta); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_del_sta failed", __func__); + goto out; + } + + ret = 0; + +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +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) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_umac_chg_sta_info chg_sta = {0}; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = -1; + + if (!if_priv || !addr) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_DBG("%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; + } + + memcpy(chg_sta.mac_addr, addr, sizeof(chg_sta.mac_addr)); + + chg_sta.sta_flags2.nrf_wifi_mask = nrf_wifi_sta_flags_to_nrf(flags_or | ~flags_and); + chg_sta.sta_flags2.nrf_wifi_set = nrf_wifi_sta_flags_to_nrf(flags_or); + + LOG_DBG("%s %x, %x", __func__, + chg_sta.sta_flags2.nrf_wifi_set, chg_sta.sta_flags2.nrf_wifi_mask); + + status = nrf_wifi_fmac_chg_sta(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &chg_sta); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_chg_sta failed", __func__); + goto out; + } + + ret = 0; + +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return ret; +} + +int nrf_wifi_wpa_supp_sta_get_inact_sec(void *if_priv, const u8 *addr) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int ret = -1, sem_ret; + int inactive_time_sec = -1; + + if (!if_priv || !addr) { + LOG_ERR("%s: Invalid params", __func__); + return ret; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_DBG("%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; + } + + status = nrf_wifi_fmac_get_station(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + (unsigned char *) addr); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_get_station failed", __func__); + goto out; + } + + sem_ret = k_sem_take(&wait_for_event_sem, K_MSEC(RPU_RESP_EVENT_TIMEOUT)); + if (sem_ret) { + LOG_ERR("%s: Timed out to get station info, ret = %d", __func__, sem_ret); + ret = NRF_WIFI_STATUS_FAIL; + goto out; + } + + inactive_time_sec = vif_ctx_zep->inactive_time_sec; +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); + return inactive_time_sec; +} +#endif /* CONFIG_NRF70_AP_MODE */ diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index c9f1ff2fae98..199ea262f589 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + dcnf: dcnf@0 { compatible = "nordic,nrf-dcnf"; reg = <0x0 0x1000>; @@ -20,6 +22,31 @@ regulators: regulator@4000 { compatible = "nordic,nrf-regulators"; reg = <0x4000 0x1000>; status = "okay"; + #address-cells = <1>; + #size-cells = <1>; + + vregmain: regulator@4704 { + compatible = "nordic,nrf5x-regulator"; + reg = <0x4704 0x1>; + status = "okay"; + regulator-name = "VREGMAIN"; + regulator-initial-mode = ; + }; + + vregradio: regulator@4904 { + compatible = "nordic,nrf5x-regulator"; + reg = <0x4904 0x1>; + status = "okay"; + regulator-name = "VREGRADIO"; + regulator-initial-mode = ; + }; + + vregh: regulator@4b00 { + compatible = "nordic,nrf53x-regulator-hv"; + reg = <0x4b00 0x44>; + status = "disabled"; + regulator-name = "VREGH"; + }; }; clock: clock@5000 { diff --git a/dts/bindings/regulator/nordic,nrf52x-regulator-hv.yaml b/dts/bindings/regulator/nordic,nrf52x-regulator-hv.yaml new file mode 100644 index 000000000000..3af5dbdff735 --- /dev/null +++ b/dts/bindings/regulator/nordic,nrf52x-regulator-hv.yaml @@ -0,0 +1,20 @@ +# Copyright (c), 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic nRF52X regulator (high voltage stage of the main supply) + +compatible: "nordic,nrf52x-regulator-hv" + +include: + - name: base.yaml + - name: regulator.yaml + property-allowlist: + - regulator-name + +properties: + reg: + required: true + + regulator-name: + required: true diff --git a/dts/bindings/regulator/nordic,nrf5x-regulator.yaml b/dts/bindings/regulator/nordic,nrf5x-regulator.yaml new file mode 100644 index 000000000000..530a0634e761 --- /dev/null +++ b/dts/bindings/regulator/nordic,nrf5x-regulator.yaml @@ -0,0 +1,24 @@ +# Copyright (c), 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic nRF5X regulator (fixed stage of the core supply) + +compatible: "nordic,nrf5x-regulator" + +include: + - name: base.yaml + - name: regulator.yaml + property-allowlist: + - regulator-name + - regulator-initial-mode + +properties: + reg: + required: true + + regulator-name: + required: true + + regulator-initial-mode: + required: true diff --git a/dts/bindings/wifi/nordic,nrf70-coex.yaml b/dts/bindings/wifi/nordic,nrf70-coex.yaml new file mode 100644 index 000000000000..208657f3fb53 --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf70-coex.yaml @@ -0,0 +1,35 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + This is a representation of an external radio coexistence setup for coexistence + with nRF70 WiFi chips. + +properties: + req-gpios: + type: phandle-array + description: | + GPIO of the SOC connected to the PTA's REQUEST pin. + + status0-gpios: + type: phandle-array + description: | + GPIO of the SOC connected to the PTA's PRIORITY pin. + This GPIO is also used to indicate direction (TX/RX). + + grant-gpios: + type: phandle-array + description: | + GPIO of the SOC connected to the PTA's GRANT pin. + + swctrl1-gpios: + type: phandle-array + description: | + GPIO of the SOC controlling the Priority (STATUS1) pin (in 4-wire + coex case) of the nRF7002 + + srrf-switch-gpios: + type: phandle-array + description: | + GPIO of the RF Switch to control SR RF output to either SR Antenna + or shared Antenna with Wi-Fi diff --git a/dts/bindings/wifi/nordic,nrf70-qspi.yaml b/dts/bindings/wifi/nordic,nrf70-qspi.yaml new file mode 100644 index 000000000000..87a98d5b3583 --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf70-qspi.yaml @@ -0,0 +1,43 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF70 Wi-Fi chip. + +include: ["nordic,nrf70.yaml", "base.yaml"] + +on-bus: qspi + +properties: + qspi-frequency: + type: int + required: true + description: | + Maximum clock speed (in Hz) supported by the device. + + reg: + required: true + + qspi-quad-mode: + type: boolean + description: | + If specified, Use QSPI in quad mode (4 IO lines) otherwise in + SPI mode (2 IO lines - MOSI & MISO). + + qspi-rx-delay: + type: int + default: 0 + description: | + Number of clock cycles from the rising edge of the SPI clock + until the input serial data is sampled. + + qspi-cpha: + type: boolean + description: | + Set to indicate phase starts with asserted half-phase (CPHA=1). + The driver using this property must also use `cpol`. + + qspi-cpol: + type: boolean + description: | + Set to indicate that the clock leading edge is falling (CPOL=1). + The driver using this property requires also use `cpha`. diff --git a/dts/bindings/wifi/nordic,nrf70-spi.yaml b/dts/bindings/wifi/nordic,nrf70-spi.yaml new file mode 100644 index 000000000000..a0363f1b1a48 --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf70-spi.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF70 Wi-Fi chip. + +include: ["nordic,nrf70.yaml", "spi-device.yaml"] diff --git a/dts/bindings/wifi/nordic,nrf70.yaml b/dts/bindings/wifi/nordic,nrf70.yaml new file mode 100644 index 000000000000..ff9021739ace --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf70.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# GPIO lines for controlling the nRF70 Series Wi-Fi chip. +include: nordic,nrf70-coex.yaml + +properties: + iovdd-ctrl-gpios: + type: phandle-array + required: true + description: GPIO of the SoC controlling IO_VDD Control pin of the nRF70 + + bucken-gpios: + type: phandle-array + required: true + description: GPIO of the SoC controlling BUCK_EN pin of the nRF70 + + host-irq-gpios: + type: phandle-array + required: true + description: GPIO of the SoC controlling the HOST_IRQ pin of the nRF70 diff --git a/dts/bindings/wifi/nordic,nrf7000-qspi.yaml b/dts/bindings/wifi/nordic,nrf7000-qspi.yaml new file mode 100644 index 000000000000..f25663749e8a --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf7000-qspi.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF7002 Wi-Fi chip with QSPI interface. + +compatible: nordic,nrf7000-qspi + +include: + - "nordic,nrf70-qspi.yaml" + - "wifi-tx-power-2g.yaml" + - "wifi-tx-power-5g.yaml" diff --git a/dts/bindings/wifi/nordic,nrf7000-spi.yaml b/dts/bindings/wifi/nordic,nrf7000-spi.yaml new file mode 100644 index 000000000000..3c5710a38f24 --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf7000-spi.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF7002 Wi-Fi chip with SPI interface. + +compatible: nordic,nrf7000-spi + +include: + - "nordic,nrf70-spi.yaml" + - "wifi-tx-power-2g.yaml" + - "wifi-tx-power-5g.yaml" diff --git a/dts/bindings/wifi/nordic,nrf7001-qspi.yaml b/dts/bindings/wifi/nordic,nrf7001-qspi.yaml new file mode 100644 index 000000000000..1961677fad2d --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf7001-qspi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF7002 Wi-Fi chip with QSPI interface. + +compatible: nordic,nrf7001-qspi + +include: + - "nordic,nrf70-qspi.yaml" + - "wifi-tx-power-2g.yaml" diff --git a/dts/bindings/wifi/nordic,nrf7001-spi.yaml b/dts/bindings/wifi/nordic,nrf7001-spi.yaml new file mode 100644 index 000000000000..5c516945e442 --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf7001-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF7002 Wi-Fi chip with SPI interface. + +compatible: nordic,nrf7001-spi + +include: + - "nordic,nrf70-spi.yaml" + - "wifi-tx-power-2g.yaml" diff --git a/dts/bindings/wifi/nordic,nrf7002-qspi.yaml b/dts/bindings/wifi/nordic,nrf7002-qspi.yaml new file mode 100644 index 000000000000..101bcfce11f0 --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf7002-qspi.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF7002 Wi-Fi chip with QSPI interface. + +compatible: nordic,nrf7002-qspi + +include: + - "nordic,nrf70-qspi.yaml" + - "wifi-tx-power-2g.yaml" + - "wifi-tx-power-5g.yaml" diff --git a/dts/bindings/wifi/nordic,nrf7002-spi.yaml b/dts/bindings/wifi/nordic,nrf7002-spi.yaml new file mode 100644 index 000000000000..af12744161a1 --- /dev/null +++ b/dts/bindings/wifi/nordic,nrf7002-spi.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of the nRF7002 Wi-Fi chip with SPI interface. + +compatible: nordic,nrf7002-spi + +include: + - "nordic,nrf70-spi.yaml" + - "wifi-tx-power-2g.yaml" + - "wifi-tx-power-5g.yaml" diff --git a/dts/bindings/wifi/wifi-tx-power-2g.yaml b/dts/bindings/wifi/wifi-tx-power-2g.yaml new file mode 100644 index 000000000000..967cee439812 --- /dev/null +++ b/dts/bindings/wifi/wifi-tx-power-2g.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + This is a representation of the Wi-Fi transmit power ceilings + i.e., maximum transmit power allowed for 2.4GHz band. Based on the + RF performance of the device, the transmit power can be limited + for different data rates and sub-bands to get the best performance. + Resolution is 1 dBm + +properties: + wifi-max-tx-pwr-2g-dsss: + type: int + required: true + description: Maximum transmit power allowed in 2.4GHz band for DSSS/CCK rates + wifi-max-tx-pwr-2g-mcs0: + type: int + required: true + description: Maximum transmit power allowed in 2.4GHz band for MCS0 + wifi-max-tx-pwr-2g-mcs7: + type: int + required: true + description: Maximum transmit power allowed in 2.4GHz band for MCS7 diff --git a/dts/bindings/wifi/wifi-tx-power-5g.yaml b/dts/bindings/wifi/wifi-tx-power-5g.yaml new file mode 100644 index 000000000000..b9af40e0b9f6 --- /dev/null +++ b/dts/bindings/wifi/wifi-tx-power-5g.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + This is a representation of the Wi-Fi transmit power ceilings + i.e., maximum transmit power allowed for 5GHz band. Based on the + RF performance of the device, the transmit power can be limited + for different data rates and sub-bands to get the best performance. + + low sub-band: Channels 36-64 + mid sub-band: Channels 96-132 + high sub-band: Channels 136-177 + + Resolution is 1 dBm + +properties: + wifi-max-tx-pwr-5g-low-mcs0: + required: true + type: int + description: Maximum transmit power allowed in 5GHz band MCS0 low sub-band + wifi-max-tx-pwr-5g-low-mcs7: + required: true + type: int + description: Maximum transmit power allowed in 5GHz band MCS7 low sub-band + wifi-max-tx-pwr-5g-mid-mcs0: + required: true + type: int + description: Maximum transmit power allowed in 5GHz band MCS0 mid sub-band + wifi-max-tx-pwr-5g-mid-mcs7: + required: true + type: int + description: Maximum transmit power allowed in 5GHz band MCS7 mid sub-band + wifi-max-tx-pwr-5g-high-mcs0: + required: true + type: int + description: Maximum transmit power allowed in 5GHz band MCS0 high sub-band + wifi-max-tx-pwr-5g-high-mcs7: + type: int + description: Maximum transmit power allowed in 5GHz band MCS7 high sub-band diff --git a/include/zephyr/dt-bindings/regulator/nrf5x.h b/include/zephyr/dt-bindings/regulator/nrf5x.h new file mode 100644 index 000000000000..d2507c74a6ea --- /dev/null +++ b/include/zephyr/dt-bindings/regulator/nrf5x.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NRF5X_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NRF_H_ + +/** + * @defgroup regulator_nrf5x nRF5X regulator devicetree helpers. + * @ingroup regulator_interface + * @{ + */ + +/** + * @name nRF5X regulator modes + * @{ + */ +/** LDO mode */ +#define NRF5X_REG_MODE_LDO 0 +/** DC/DC mode */ +#define NRF5X_REG_MODE_DCDC 1 +/** @} */ + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NRF5X_H_*/ diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 30fbb200bce4..e49a381c45ce 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -92,6 +92,9 @@ struct net_eth_addr { #if !defined(ETH_P_ECAT) #define ETH_P_ECAT NET_ETH_PTYPE_ECAT #endif +#if !defined(ETH_P_EAPOL) +#define ETH_P_EAPOL NET_ETH_PTYPE_EAPOL +#endif #if !defined(ETH_P_IEEE802154) #define ETH_P_IEEE802154 NET_ETH_PTYPE_IEEE802154 #endif diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index b1a2ca8925a1..54205794b5e4 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -3013,6 +3013,20 @@ bool net_if_is_wifi(struct net_if *iface); */ struct net_if *net_if_get_first_wifi(void); +/** + * @brief Get Wi-Fi network station interface. + * + * @return Pointer to network interface, NULL if not found. + */ +struct net_if *net_if_get_wifi_sta(void); + +/** + * @brief Get first Wi-Fi network Soft-AP interface. + * + * @return Pointer to network interface, NULL if not found. + */ +struct net_if *net_if_get_wifi_sap(void); + /** * @brief Get network interface name. * diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index deab64cc7562..cce48e90c84d 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -978,7 +978,7 @@ struct net_wifi_mgmt_offload { #if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT) || defined(__DOXYGEN__) /** Wi-Fi supplicant driver API */ - void *wifi_drv_ops; + const void *wifi_drv_ops; #endif }; diff --git a/include/zephyr/net/wifi_nm.h b/include/zephyr/net/wifi_nm.h index 615d49157572..a09cbd626b7f 100644 --- a/include/zephyr/net/wifi_nm.h +++ b/include/zephyr/net/wifi_nm.h @@ -30,6 +30,24 @@ extern "C" { #endif +/** Types of Wi-Fi interface */ +enum wifi_nm_iface_type { + /** IEEE 802.11 Wi-Fi Station */ + WIFI_TYPE_STA = 0, + /** IEEE 802.11 Wi-Fi Soft AP */ + WIFI_TYPE_SAP, +}; + +/** + * @brief WiFi Network Managed interfaces + */ +struct wifi_nm_mgd_iface { + /** Wi-Fi interface type */ + unsigned char type; + /** Managed net interfaces */ + struct net_if *iface; +}; + /** * @brief WiFi Network manager instance */ @@ -39,7 +57,7 @@ struct wifi_nm_instance { /** Wi-Fi Management operations */ const struct wifi_mgmt_ops *ops; /** List of Managed interfaces */ - struct net_if *mgd_ifaces[CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES]; + struct wifi_nm_mgd_iface mgd_ifaces[CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES]; }; /** @cond INTERNAL_HIDDEN */ @@ -50,7 +68,7 @@ struct wifi_nm_instance { static STRUCT_SECTION_ITERABLE(wifi_nm_instance, WIFI_NM_NAME(_name)) = { \ .name = STRINGIFY(_name), \ .ops = _ops, \ - .mgd_ifaces = { NULL }, \ + .mgd_ifaces = {}, \ } /** @endcond */ @@ -71,6 +89,14 @@ struct wifi_nm_instance *wifi_nm_get_instance(const char *name); */ struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface); +/** + * @brief Get a Wi-Fi type for a given interface + * + * @param iface Interface + * + */ +unsigned char wifi_nm_get_type_iface(struct net_if *iface); + /** * @brief Register a managed interface * @@ -84,6 +110,21 @@ struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface); */ int wifi_nm_register_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface); +/** + * @brief Register a managed interface + * + * @param nm Pointer to Network manager instance + * @param type Wi-Fi type + * @param iface Managed interface + * + * @retval 0 If successful. + * @retval -EINVAL If invalid parameters were passed. + * @retval -ENOTSUP If the interface is not a Wi-Fi interface. + * @retval -ENOMEM If the maximum number of managed interfaces has been reached. + */ +int wifi_nm_register_mgd_type_iface(struct wifi_nm_instance *nm, + enum wifi_nm_iface_type type, struct net_if *iface); + /** * @brief Unregister managed interface * diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt index b340c3882c8b..8fe12ad27018 100644 --- a/modules/hostap/CMakeLists.txt +++ b/modules/hostap/CMakeLists.txt @@ -16,6 +16,7 @@ set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -lnosys") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMISSING_SYSCALL_NAMES") zephyr_include_directories( + src/ ${HOSTAP_BASE}/ ${WIFI_NM_WPA_SUPPLICANT_BASE}/ ${HOSTAP_SRC_BASE}/ @@ -25,10 +26,11 @@ zephyr_library_compile_definitions( TLS_DEFAULT_CIPHERS=\""DEFAULT:!EXP:!LOW"\" CONFIG_SME CONFIG_NO_CONFIG_WRITE - CONFIG_NO_CONFIG_BLOBS CONFIG_CTRL_IFACE CONFIG_NO_RANDOM_POOL CONFIG_SHA256 + CONFIG_SHA384 + CONFIG_SHA512 CONFIG_CTRL_IFACE_ZEPHYR CONFIG_SUITEB192 ) @@ -76,10 +78,6 @@ zephyr_library_include_directories( ${ZEPHYR_BASE}/include/net ) -zephyr_library_compile_definitions_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO - CONFIG_NO_PBKDF2 -) - zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_NO_DEBUG CONFIG_NO_STDOUT_DEBUG ) @@ -93,6 +91,7 @@ zephyr_library_sources( ${HOSTAP_SRC_BASE}/drivers/driver_common.c ${HOSTAP_SRC_BASE}/drivers/drivers.c + ${HOSTAP_SRC_BASE}/utils/crc32.c ${HOSTAP_SRC_BASE}/utils/base64.c ${HOSTAP_SRC_BASE}/utils/common.c ${HOSTAP_SRC_BASE}/utils/wpabuf.c @@ -159,6 +158,7 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_AP ${HOSTAP_SRC_BASE}/ap/bss_load.c ${HOSTAP_SRC_BASE}/ap/dfs.c ${HOSTAP_SRC_BASE}/ap/drv_callbacks.c + ${HOSTAP_SRC_BASE}/ap/ctrl_iface_ap.c ${HOSTAP_SRC_BASE}/ap/eap_user_db.c ${HOSTAP_SRC_BASE}/ap/hostapd.c ${HOSTAP_SRC_BASE}/ap/hw_features.c @@ -225,17 +225,6 @@ zephyr_library_sources_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE ${HOSTAP_SRC_BASE}/rsn_supp/wpa.c ${HOSTAP_SRC_BASE}/rsn_supp/preauth.c ${HOSTAP_SRC_BASE}/rsn_supp/wpa_ie.c - ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-bignum.c - ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-ec.c - ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls.c - ${HOSTAP_SRC_BASE}/crypto/tls_mbedtls.c - ${HOSTAP_SRC_BASE}/crypto/aes-wrap.c - ${HOSTAP_SRC_BASE}/crypto/aes-unwrap.c - ${HOSTAP_SRC_BASE}/crypto/rc4.c - ${HOSTAP_SRC_BASE}/crypto/sha1-prf.c - ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c - ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c - ${HOSTAP_SRC_BASE}/crypto/sha384-prf.c ) zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 @@ -243,7 +232,6 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 ${HOSTAP_SRC_BASE}/common/dragonfly.c ${HOSTAP_SRC_BASE}/crypto/dh_groups.c - ${HOSTAP_SRC_BASE}/crypto/sha256-kdf.c ) zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 @@ -255,9 +243,6 @@ zephyr_library_include_directories_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_N ${CMAKE_SOURCE_DIR} ) -zephyr_library_link_libraries_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE - mbedTLS) - zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P ${WIFI_NM_WPA_SUPPLICANT_BASE}/p2p_supplicant.c ${WIFI_NM_WPA_SUPPLICANT_BASE}/p2p_supplicant_sd.c @@ -305,26 +290,7 @@ zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS EAP_WSC ) -zephyr_library_sources_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE - ${HOSTAP_SRC_BASE}/common/wpa_common.c - ${HOSTAP_SRC_BASE}/rsn_supp/wpa.c - ${HOSTAP_SRC_BASE}/rsn_supp/preauth.c - ${HOSTAP_SRC_BASE}/rsn_supp/wpa_ie.c - - ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-bignum.c - ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-ec.c - ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls.c - ${HOSTAP_SRC_BASE}/crypto/aes-wrap.c - ${HOSTAP_SRC_BASE}/crypto/aes-unwrap.c - ${HOSTAP_SRC_BASE}/crypto/rc4.c - ${HOSTAP_SRC_BASE}/crypto/sha1-prf.c - ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c - ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c - ${HOSTAP_SRC_BASE}/crypto/sha384-prf.c -) - zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE - ${HOSTAP_SRC_BASE}/crypto/tls_mbedtls.c ${HOSTAP_SRC_BASE}/eap_peer/eap_tls.c ${HOSTAP_SRC_BASE}/eap_peer/eap_tls_common.c @@ -364,35 +330,28 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE ${HOSTAP_SRC_BASE}/eap_common/eap_ikev2_common.c ${HOSTAP_SRC_BASE}/eap_common/ikev2_common.c - # common - ${HOSTAP_SRC_BASE}/crypto/sha384-tlsprf.c - ${HOSTAP_SRC_BASE}/crypto/sha256-tlsprf.c - ${HOSTAP_SRC_BASE}/crypto/sha1-tlsprf.c - ${HOSTAP_SRC_BASE}/crypto/sha1-tprf.c - ${HOSTAP_SRC_BASE}/crypto/ms_funcs.c - ${HOSTAP_SRC_BASE}/crypto/aes-eax.c - # MD4 removed from MbedTLS - ${HOSTAP_SRC_BASE}/crypto/md4-internal - ${HOSTAP_SRC_BASE}/crypto/aes-encblock.c - ) zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE - CONFIG_EAP_TLS - CONFIG_IEEE8021X_EAPOL - CONFIG_EAP_PEAP - CONFIG_EAP_TTLS - CONFIG_EAP_MD5 - CONFIG_EAP_MSCHAPv2 - CONFIG_EAP_LEAP - CONFIG_EAP_PSK - CONFIG_EAP_FAST - CONFIG_EAP_PAX - CONFIG_EAP_SAKE - CONFIG_EAP_GPSK - CONFIG_EAP_PWD - CONFIG_EAP_EKE - CONFIG_EAP_IKEv2 + EAP_TLS + IEEE8021X_EAPOL + EAP_PEAP + EAP_TTLS + EAP_MD5 + EAP_MSCHAPv2 + EAP_LEAP + EAP_PSK + EAP_FAST + EAP_PAX + EAP_SAKE + EAP_GPSK + EAP_PWD + EAP_EKE + EAP_IKEv2 +) + +zephyr_library_compile_definitions_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + CONFIG_NO_CONFIG_BLOBS ) zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL @@ -404,10 +363,117 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL ) zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL - CONFIG_IEEE8021X_EAPOL + IEEE8021X_EAPOL ) zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_NW_SEL_RELIABILITY CONFIG_NW_SEL_RELIABILITY ) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP + ${WIFI_NM_WPA_SUPPLICANT_BASE}/dpp_supplicant.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/offchannel.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/gas_query.c + + ${HOSTAP_SRC_BASE}/ap/dpp_hostapd.c + ${HOSTAP_SRC_BASE}/ap/gas_query_ap.c + ${HOSTAP_SRC_BASE}/ap/gas_serv.c + + ${HOSTAP_SRC_BASE}/common/dpp_tcp.c + ${HOSTAP_SRC_BASE}/common/dpp.c + ${HOSTAP_SRC_BASE}/common/dpp_pkex.c + ${HOSTAP_SRC_BASE}/common/dpp_crypto.c + ${HOSTAP_SRC_BASE}/common/dpp_auth.c + ${HOSTAP_SRC_BASE}/common/dpp_reconfig.c + ${HOSTAP_SRC_BASE}/common/gas_server.c + ${HOSTAP_SRC_BASE}/common/gas.c + ${HOSTAP_SRC_BASE}/common/dpp_backup.c + + ${HOSTAP_SRC_BASE}/crypto/aes-siv.c + + ${HOSTAP_SRC_BASE}/utils/json.c + ${HOSTAP_SRC_BASE}/utils/ip_addr.c + + ${HOSTAP_SRC_BASE}/tls/asn1.c +) + +# crypto mbedtls related CRYPTO OR LEGACY_NCS +if(DEFINED CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO OR + DEFINED CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_LEGACY_NCS OR + DEFINED CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_LEGACY_NCS_PSA) +zephyr_library_sources( + ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-bignum.c + ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-ec.c + ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls.c + ${HOSTAP_SRC_BASE}/crypto/aes-internal.c + ${HOSTAP_SRC_BASE}/crypto/aes-wrap.c + ${HOSTAP_SRC_BASE}/crypto/aes-unwrap.c + ${HOSTAP_SRC_BASE}/crypto/rc4.c + ${HOSTAP_SRC_BASE}/crypto/sha1-internal.c + ${HOSTAP_SRC_BASE}/crypto/sha1-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha1-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-kdf.c + ${HOSTAP_SRC_BASE}/crypto/sha384-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha384-kdf.c + ${HOSTAP_SRC_BASE}/crypto/sha512-internal.c + ${HOSTAP_SRC_BASE}/crypto/sha512.c + ${HOSTAP_SRC_BASE}/crypto/sha512-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha512-kdf.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 + ${HOSTAP_SRC_BASE}/crypto/sha256-kdf.c +) + +zephyr_library_sources_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + ${HOSTAP_SRC_BASE}/crypto/tls_none.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + # common + ${HOSTAP_SRC_BASE}/crypto/sha384-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha1-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha1-tprf.c + ${HOSTAP_SRC_BASE}/crypto/ms_funcs.c + ${HOSTAP_SRC_BASE}/crypto/aes-eax.c + # MD4 removed from MbedTLS + ${HOSTAP_SRC_BASE}/crypto/md4-internal.c + ${HOSTAP_SRC_BASE}/crypto/aes-encblock.c + ${HOSTAP_SRC_BASE}/crypto/tls_mbedtls.c +) +endif() + +if(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT) +zephyr_include_directories( + ${HOSTAP_BASE}/port/mbedtls +) + +zephyr_library_sources( + ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls_alt.c + ${HOSTAP_SRC_BASE}/crypto/tls_mbedtls_alt.c + ${HOSTAP_SRC_BASE}/crypto/rc4.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA + ${HOSTAP_BASE}/port/mbedtls/supp_psa_api.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + ${HOSTAP_SRC_BASE}/crypto/ms_funcs.c + ${HOSTAP_SRC_BASE}/crypto/aes-eax.c + ${HOSTAP_SRC_BASE}/crypto/md4-internal.c + ${HOSTAP_SRC_BASE}/crypto/fips_prf_internal.c + ${HOSTAP_SRC_BASE}/crypto/milenage.c +) +endif() + +zephyr_library_link_libraries_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + mbedTLS) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT + MBEDTLS_NIST_KW_C +) + endif() diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index 473b6278055c..2aa457b3586f 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -10,6 +10,7 @@ config WIFI_NM_WPA_SUPPLICANT select POSIX_CLOCK select POSIX_SIGNAL select POSIX_API + select FILE_SYSTEM select NET_SOCKETS select NET_SOCKETS_PACKET select NET_SOCKETPAIR @@ -35,7 +36,7 @@ config WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE config WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE int "Stack size for wpa_supplicant iface workqueue" - default 4096 + default 6144 config WIFI_NM_WPA_SUPPLICANT_WQ_PRIO int "Thread priority of wpa_supplicant iface workqueue" @@ -103,9 +104,11 @@ config WIFI_NM_WPA_SUPPLICANT_WEP choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND prompt "WPA supplicant crypto implementation" - default WIFI_NM_WPA_SUPPLICANT_CRYPTO + default WIFI_NM_WPA_SUPPLICANT_CRYPTO_LEGACY_NCS help Select the crypto implementation to use for WPA supplicant. + WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT support enterprise + and DPP. And use Mbedtls PSA apis for HW acceleration. config WIFI_NM_WPA_SUPPLICANT_CRYPTO bool "Crypto support for WiFi" @@ -125,11 +128,80 @@ config WIFI_NM_WPA_SUPPLICANT_CRYPTO select MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT + bool "Crypto Mbedtls alt support for WiFi" + select MBEDTLS + select MBEDTLS_CIPHER_MODE_CTR_ENABLED + select MBEDTLS_CIPHER_MODE_CBC_ENABLED + select MBEDTLS_ECP_C + select MBEDTLS_ECP_ALL_ENABLED + select MBEDTLS_CMAC_C + select MBEDTLS_PKCS5_C + select MBEDTLS_PK_WRITE_C + select MBEDTLS_ECDH_C + select MBEDTLS_ECDSA_C + select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + select MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + select MBEDTLS_DHM_C + select MBEDTLS_HKDF_C + select MBEDTLS_SERVER_NAME_INDICATION + select MBEDTLS_X509_CRL_PARSE_C + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_LEGACY_NCS + bool "Legacy Crypto support for WiFi using nRF security" + select MBEDTLS + select NRF_SECURITY + select MBEDTLS_CIPHER_MODE_CBC + select MBEDTLS_CIPHER_MODE_CTR + select MBEDTLS_LEGACY_CRYPTO_C + select MBEDTLS_SHA1_C + select MBEDTLS_ECP_C + select MBEDTLS_CTR_DRBG_C + select MBEDTLS_PK_C + select MBEDTLS_PKCS5_C + select MBEDTLS_PK_PARSE_C + select MBEDTLS_CMAC_C + select MBEDTLS_CIPHER_PADDING_PKCS7 + select MBEDTLS_PK_WRITE_C + select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_LEGACY_NCS_PSA + bool "PSA Crypto support for WiFi using nRF security" + select MBEDTLS + select NRF_SECURITY + select PSA_WANT_GENERATE_RANDOM + # Legacy crypto, still needed + select MBEDTLS_SHA1_C + select MBEDTLS_LEGACY_CRYPTO_C + select MBEDTLS_CMAC_C + select MBEDTLS_GCM_C + select MBEDTLS_TLS_LIBRARY + select MBEDTLS_PK_C + select MBEDTLS_PK_WRITE_C + select MBEDTLS_X509_LIBRARY + select MBEDTLS_X509_CRT_PARSE_C + select MBEDTLS_CIPHER_C + select MBEDTLS_CIPHER_MODE_CTR + select MBEDTLS_CIPHER_MODE_CBC + select MBEDTLS_SSL_TLS_C + select MBEDTLS_ECP_C + select MBEDTLS_CTR_DRBG_C + select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + select MBEDTLS_MD_C + select MBEDTLS_CIPHER_PADDING_PKCS7 + select MBEDTLS_PKCS5_C + config WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE bool "No Crypto support for WiFi" endchoice +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA + bool "Crypto Platform Secure Architecture support for WiFi" + default y if WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT + help + Support Mbedtls 3.x to use PSA apis instead of legacy apis. + config WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE bool "Enterprise Crypto support for WiFi" depends on !WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE @@ -174,6 +246,24 @@ config WIFI_NM_WPA_SUPPLICANT_BSS_MAX_IDLE_TIME config WIFI_NM_WPA_SUPPLICANT_NO_DEBUG bool "Disable printing of debug messages, saves code size significantly" + +config WIFI_NM_WPA_SUPPLICANT_DPP + bool "WFA Easy Connect DPP" + select DPP + select DPP2 + select DPP3 + select GAS + select GAS_SERVER + select OFFCHANNEL + select MBEDTLS_X509_CSR_WRITE_C + select MBEDTLS_X509_CSR_PARSE_C + + +config WPA_CLI + bool "WPA CLI support" + help + Enable WPA CLI support for wpa_supplicant. + # Create hidden config options that are used in hostap. This way we do not need # to mark them as allowed for CI checks, and also someone else cannot use the # same name options. @@ -188,7 +278,7 @@ config NO_CONFIG_WRITE config NO_CONFIG_BLOBS bool - default y + default y if !WIFI_NM_WPA_SUPPLICANT_DPP && !WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE config CTRL_IFACE bool @@ -211,7 +301,7 @@ config NO_WPA config NO_PBKDF2 bool - default y + default y if WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE config SAE_PK bool @@ -254,6 +344,9 @@ config P2P config GAS bool +config GAS_SERVER + bool + config OFFCHANNEL bool @@ -329,6 +422,12 @@ config SAE config SHA256 bool +config SHA384 + bool + +config SHA512 + bool + config SUITEB192 bool @@ -336,9 +435,6 @@ config WEP bool default y if WIFI_NM_WPA_SUPPLICANT_WEP -config WPA_CLI - bool - config WPA_CRYPTO bool @@ -358,6 +454,15 @@ config RRM config WMM_AC bool +config DPP + bool + +config DPP2 + bool + +config DPP3 + bool + config NW_SEL_RELIABILITY bool default y diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c index 69a4dd8438b1..43d438044bd9 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -14,6 +14,9 @@ LOG_MODULE_REGISTER(wifi_supplicant, CONFIG_WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL); #if !defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) #include #endif /* !CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE && !CONFIG_MBEDTLS_ENABLE_HEAP */ +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA +#include "supp_psa_api.h" +#endif #include #include @@ -229,7 +232,9 @@ static int add_interface(struct supplicant_context *ctx, struct net_if *iface) goto out; } - ret = wifi_nm_register_mgd_iface(wifi_nm_get_instance("wifi_supplicant"), iface); + ret = wifi_nm_register_mgd_type_iface(wifi_nm_get_instance("wifi_supplicant"), + WIFI_TYPE_STA, + iface); if (ret) { LOG_ERR("Failed to register mgd iface with native stack %s (%d)", ifname, ret); @@ -409,7 +414,7 @@ static void iface_cb(struct net_if *iface, void *user_data) return; } - if (!net_if_is_up(iface)) { + if (!net_if_is_admin_up(iface)) { return; } @@ -523,6 +528,10 @@ static void handler(void) mbedtls_platform_set_calloc_free(calloc, free); #endif /* !CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE && !CONFIG_MBEDTLS_ENABLE_HEAP */ +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_MBEDTLS_PSA + supp_psa_crypto_init(); +#endif + ctx = get_default_context(); k_work_queue_init(&ctx->iface_wq); diff --git a/modules/hostap/src/wpa_cli.c b/modules/hostap/src/wpa_cli.c index cbd66b1279d0..1ea6be54a5da 100644 --- a/modules/hostap/src/wpa_cli.c +++ b/modules/hostap/src/wpa_cli.c @@ -29,7 +29,7 @@ static int cmd_wpa_cli(const struct shell *sh, argc++; /* Remove wpa_cli from the argument list */ - return z_wpa_ctrl_zephyr_cmd(argc - 1, &argv[1]); + return zephyr_wpa_ctrl_zephyr_cmd(argc - 1, &argv[1]); } /* Persisting with "wpa_cli" naming for compatibility with Wi-Fi diff --git a/samples/net/dhcpv4_client/overlay-nrf700x.conf b/samples/net/dhcpv4_client/overlay-nrf700x.conf deleted file mode 100644 index 2d552e9c6231..000000000000 --- a/samples/net/dhcpv4_client/overlay-nrf700x.conf +++ /dev/null @@ -1,14 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/dns_resolve/overlay-nrf700x.conf b/samples/net/dns_resolve/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/dns_resolve/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/ipv4_autoconf/overlay-nrf700x.conf b/samples/net/ipv4_autoconf/overlay-nrf700x.conf deleted file mode 100644 index 2d552e9c6231..000000000000 --- a/samples/net/ipv4_autoconf/overlay-nrf700x.conf +++ /dev/null @@ -1,14 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/lwm2m_client/overlay-nrf700x.conf b/samples/net/lwm2m_client/overlay-nrf700x.conf index 2409886fe420..a1c70559c768 100644 --- a/samples/net/lwm2m_client/overlay-nrf700x.conf +++ b/samples/net/lwm2m_client/overlay-nrf700x.conf @@ -5,7 +5,6 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 # Wi-Fi CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y CONFIG_WIFI_MGMT_EXT=y CONFIG_NRF_WIFI_IF_AUTO_START=n @@ -16,8 +15,8 @@ CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" # WPA -CONFIG_WPA_SUPP=y -CONFIG_WPA_SUPP_LOG_LEVEL_ERR=y +CONFIG_WIFI_NM_WPA_SUPPLICANT=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL_ERR=y CONFIG_NET_NATIVE=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/mdns_responder/overlay-nrf700x.conf b/samples/net/mdns_responder/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/mdns_responder/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/mqtt_publisher/overlay-nrf700x.conf b/samples/net/mqtt_publisher/overlay-nrf700x.conf deleted file mode 100644 index a812c7896f62..000000000000 --- a/samples/net/mqtt_publisher/overlay-nrf700x.conf +++ /dev/null @@ -1,19 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_CONFIG_NEED_IPV4=y -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/mqtt_sn_publisher/overlay-nrf700x.conf b/samples/net/mqtt_sn_publisher/overlay-nrf700x.conf deleted file mode 100644 index cbc47b965727..000000000000 --- a/samples/net/mqtt_sn_publisher/overlay-nrf700x.conf +++ /dev/null @@ -1,20 +0,0 @@ -CONFIG_POSIX_MAX_FDS=16 - -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/coap_client/overlay-nrf700x.conf b/samples/net/sockets/coap_client/overlay-nrf700x.conf deleted file mode 100644 index a0e436e3537d..000000000000 --- a/samples/net/sockets/coap_client/overlay-nrf700x.conf +++ /dev/null @@ -1,16 +0,0 @@ -CONFIG_HEAP_MEM_POOL_SIZE=153000 - -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/coap_server/overlay-nrf700x.conf b/samples/net/sockets/coap_server/overlay-nrf700x.conf deleted file mode 100644 index 4817a4f73ba6..000000000000 --- a/samples/net/sockets/coap_server/overlay-nrf700x.conf +++ /dev/null @@ -1,26 +0,0 @@ -CONFIG_HEAP_MEM_POOL_SIZE=153000 - -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# The sample can run either IPv4 or IPv6, not both -CONFIG_NET_IPV6=n -CONFIG_NET_CONFIG_NEED_IPV6=n -CONFIG_NET_IPV4=y -CONFIG_NET_CONFIG_NEED_IPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo/overlay-nrf700x.conf b/samples/net/sockets/echo/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/sockets/echo/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo_async/overlay-nrf700x.conf b/samples/net/sockets/echo_async/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/sockets/echo_async/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo_client/overlay-nrf700x.conf b/samples/net/sockets/echo_client/overlay-nrf700x.conf deleted file mode 100644 index cbc47b965727..000000000000 --- a/samples/net/sockets/echo_client/overlay-nrf700x.conf +++ /dev/null @@ -1,20 +0,0 @@ -CONFIG_POSIX_MAX_FDS=16 - -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo_server/overlay-nrf700x.conf b/samples/net/sockets/echo_server/overlay-nrf700x.conf deleted file mode 100644 index cbc47b965727..000000000000 --- a/samples/net/sockets/echo_server/overlay-nrf700x.conf +++ /dev/null @@ -1,20 +0,0 @@ -CONFIG_POSIX_MAX_FDS=16 - -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/http_get/overlay-nrf700x.conf b/samples/net/sockets/http_get/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/sockets/http_get/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/sntp_client/overlay-nrf700x.conf b/samples/net/sockets/sntp_client/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/sockets/sntp_client/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/syslog_net/overlay-nrf700x.conf b/samples/net/syslog_net/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/syslog_net/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/telnet/overlay-nrf700x.conf b/samples/net/telnet/overlay-nrf700x.conf deleted file mode 100644 index aa59e5d5ea2d..000000000000 --- a/samples/net/telnet/overlay-nrf700x.conf +++ /dev/null @@ -1,18 +0,0 @@ -# Wi-Fi -CONFIG_WIFI=y -CONFIG_WIFI_NRF700X=y -CONFIG_WPA_SUPP=y -CONFIG_NET_L2_ETHERNET=y - -# DHCPv4 -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_DHCPV4=y - -# Connection manager -CONFIG_NET_CONNECTION_MANAGER=y - -# Credentials -CONFIG_WIFI_CREDENTIALS=y -CONFIG_WIFI_CREDENTIALS_STATIC=y -CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" -CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/wifi/prj.conf b/samples/net/wifi/prj.conf index de7de625340f..e1a1b40a4098 100644 --- a/samples/net/wifi/prj.conf +++ b/samples/net/wifi/prj.conf @@ -3,6 +3,8 @@ CONFIG_EARLY_CONSOLE=y CONFIG_NETWORKING=y CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_MAIN_STACK_SIZE=5200 +CONFIG_SHELL_STACK_SIZE=5200 CONFIG_NET_TX_STACK_SIZE=2048 CONFIG_NET_RX_STACK_SIZE=2048 @@ -29,3 +31,8 @@ CONFIG_NET_STATISTICS_PERIODIC_OUTPUT=n CONFIG_WIFI=y CONFIG_WIFI_LOG_LEVEL_ERR=y CONFIG_NET_L2_WIFI_SHELL=y +# printing of scan results puts pressure on queues in new locking +# design in net_mgmt. So, use a higher timeout for a crowded +# environment. +CONFIG_NET_MGMT_EVENT_QUEUE_TIMEOUT=5000 +CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=16 diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 50241b398426..0f5c6d6c9605 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -948,6 +948,7 @@ def check_no_undef_outside_kconfig(self, kconf): "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", diff --git a/subsys/net/conn_mgr/Kconfig b/subsys/net/conn_mgr/Kconfig index 541edf0e63ec..71e8b728e6c9 100644 --- a/subsys/net/conn_mgr/Kconfig +++ b/subsys/net/conn_mgr/Kconfig @@ -24,7 +24,7 @@ source "subsys/net/Kconfig.template.log_config.net" config NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE int "Size of the stack allocated for the conn_mgr_monitor thread" - default 8192 if WPA_SUPP + default 8192 if WIFI_NM_WPA_SUPPLICANT default 512 help Sets the stack size which will be used by the connection manager for connectivity monitoring. diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index dc115aaf2c32..8e431241f51f 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -22,6 +22,9 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL); #include #include #include +#ifdef CONFIG_WIFI_NM +#include +#endif #include #include #include @@ -5568,6 +5571,40 @@ struct net_if *net_if_get_first_wifi(void) return NULL; } +struct net_if *net_if_get_wifi_sta(void) +{ + struct ethernet_context *eth_ctx = NULL; + + STRUCT_SECTION_FOREACH(net_if, iface) { + eth_ctx = net_if_l2_data(iface); + if (net_if_is_wifi(iface) +#ifdef CONFIG_WIFI_NM + && (wifi_nm_get_type_iface(iface) == (1 << WIFI_TYPE_STA)) +#endif + ) { + return iface; + } + } + return NULL; +} + +struct net_if *net_if_get_wifi_sap(void) +{ + struct ethernet_context *eth_ctx = NULL; + + STRUCT_SECTION_FOREACH(net_if, iface) { + eth_ctx = net_if_l2_data(iface); + if (net_if_is_wifi(iface) +#ifdef CONFIG_WIFI_NM + && (wifi_nm_get_type_iface(iface) == (1 << WIFI_TYPE_SAP)) +#endif + ) { + return iface; + } + } + return NULL; +} + int net_if_get_name(struct net_if *iface, char *buf, int len) { #if defined(CONFIG_NET_INTERFACE_NAME) diff --git a/subsys/net/l2/wifi/wifi_nm.c b/subsys/net/l2/wifi/wifi_nm.c index 588992634bf2..74225cf04548 100644 --- a/subsys/net/l2/wifi/wifi_nm.c +++ b/subsys/net/l2/wifi/wifi_nm.c @@ -33,7 +33,7 @@ struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface) k_mutex_lock(&wifi_nm_lock, K_FOREVER); STRUCT_SECTION_FOREACH(wifi_nm_instance, nm) { for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { - if (nm->mgd_ifaces[i] == iface) { + if (nm->mgd_ifaces[i].iface == iface) { k_mutex_unlock(&wifi_nm_lock); return nm; } @@ -44,6 +44,26 @@ struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface) return NULL; } +unsigned char wifi_nm_get_type_iface(struct net_if *iface) +{ + if (!iface || !net_if_is_wifi(iface)) { + return 0; + } + + k_mutex_lock(&wifi_nm_lock, K_FOREVER); + STRUCT_SECTION_FOREACH(wifi_nm_instance, nm) { + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (nm->mgd_ifaces[i].iface == iface) { + k_mutex_unlock(&wifi_nm_lock); + return nm->mgd_ifaces[i].type; + } + } + } + + k_mutex_unlock(&wifi_nm_lock); + return 0; +} + int wifi_nm_register_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface) { if (!nm || !iface) { @@ -56,8 +76,38 @@ int wifi_nm_register_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface k_mutex_lock(&wifi_nm_lock, K_FOREVER); for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { - if (!nm->mgd_ifaces[i]) { - nm->mgd_ifaces[i] = iface; + if (nm->mgd_ifaces[i].iface == iface) { + k_mutex_unlock(&wifi_nm_lock); + return 0; + } + + if (!nm->mgd_ifaces[i].iface) { + nm->mgd_ifaces[i].iface = iface; + k_mutex_unlock(&wifi_nm_lock); + return 0; + } + } + k_mutex_unlock(&wifi_nm_lock); + + return -ENOMEM; +} + +int wifi_nm_register_mgd_type_iface(struct wifi_nm_instance *nm, + enum wifi_nm_iface_type type, struct net_if *iface) +{ + if (!nm || !iface) { + return -EINVAL; + } + + if (!net_if_is_wifi(iface)) { + return -ENOTSUP; + } + + k_mutex_lock(&wifi_nm_lock, K_FOREVER); + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (!nm->mgd_ifaces[i].iface) { + nm->mgd_ifaces[i].iface = iface; + nm->mgd_ifaces[i].type = (1 << type); k_mutex_unlock(&wifi_nm_lock); return 0; } @@ -75,8 +125,8 @@ int wifi_nm_unregister_mgd_iface(struct wifi_nm_instance *nm, struct net_if *ifa k_mutex_lock(&wifi_nm_lock, K_FOREVER); for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { - if (nm->mgd_ifaces[i] == iface) { - nm->mgd_ifaces[i] = NULL; + if (nm->mgd_ifaces[i].iface == iface) { + nm->mgd_ifaces[i].iface = NULL; k_mutex_unlock(&wifi_nm_lock); return 0; } diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c68c1c07cb59..5adad439a046 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -607,7 +607,7 @@ static int __wifi_args_to_params(const struct shell *sh, size_t argc, char *argv static int cmd_wifi_connect(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_first_wifi(); + struct net_if *iface = net_if_get_wifi_sta(); struct wifi_connect_req_params cnx_params = { 0 }; int ret; @@ -634,7 +634,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_first_wifi(); + struct net_if *iface = net_if_get_wifi_sta(); int status; context.disconnecting = true; @@ -1283,7 +1283,7 @@ static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_first_wifi(); + struct net_if *iface = net_if_get_wifi_sap(); static struct wifi_connect_req_params cnx_params; int ret; @@ -1310,7 +1310,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_first_wifi(); + struct net_if *iface = net_if_get_wifi_sap(); int ret; ret = net_mgmt(NET_REQUEST_WIFI_AP_DISABLE, iface, NULL, 0); diff --git a/west.yml b/west.yml index b77d741b71d7..c4d0f1478907 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nordic - revision: ab5cb2e2faeb1edfad7a25286dcb513929ae55da + revision: 91654ddc7ce0da523eb4d6be2171208ae2b8fb35 path: modules/hal/nordic groups: - hal @@ -256,7 +256,7 @@ manifest: - name: hostap repo-path: hostap path: modules/lib/hostap - revision: 83574f533fb5c6808af0d9872741d72d48be2f98 + revision: 77a4cad575c91f1b234c8d15630f87999881cde2 - name: libmetal revision: 243eed541b9c211a2ce8841c788e62ddce84425e path: modules/hal/libmetal