diff --git a/.github/workflows/doc-publish.yml b/.github/workflows/doc-publish.yml
index b2f6fc5edc57c..b50731889fe02 100644
--- a/.github/workflows/doc-publish.yml
+++ b/.github/workflows/doc-publish.yml
@@ -56,7 +56,7 @@ jobs:
- name: install-pkgs
run: |
- sudo apt-get install -y ninja-build doxygen
+ sudo apt-get install -y ninja-build doxygen graphviz
- name: cache-pip
uses: actions/cache@v1
diff --git a/.github/workflows/footprint-tracking.yml b/.github/workflows/footprint-tracking.yml
new file mode 100644
index 0000000000000..caa1957daf3a6
--- /dev/null
+++ b/.github/workflows/footprint-tracking.yml
@@ -0,0 +1,68 @@
+name: Footprint Tracking
+
+# Run every 12 hours and on tags
+on:
+ schedule:
+ - cron: '50 1/12 * * *'
+ push:
+ paths:
+ - 'VERSION'
+ - '.github/workflows/footprint-tracking.yml'
+ tags:
+ # only publish v* tags, do not care about zephyr-v* which point to the
+ # same commit
+ - 'v*'
+
+jobs:
+ footprint-tracking-cancel:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Cancel Previous Runs
+ uses: styfle/cancel-workflow-action@0.6.0
+ with:
+ access_token: ${{ github.token }}
+ footprint-tracking:
+ runs-on: ubuntu-latest
+ needs: footprint-tracking-cancel
+ container:
+ image: zephyrprojectrtos/ci:v0.17.1
+ options: '--entrypoint /bin/bash'
+ strategy:
+ fail-fast: false
+ env:
+ ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.12.4
+ CLANG_ROOT_DIR: /usr/lib/llvm-12
+ ZEPHYR_TOOLCHAIN_VARIANT: zephyr
+ steps:
+ - name: Update PATH for west
+ run: |
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
+ - name: Install pip packages
+ run: |
+ sudo pip3 install -U setuptools wheel pip gitpython
+
+ - name: checkout
+ uses: actions/checkout@v2
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+
+ - name: west setup
+ run: |
+ west init -l . || true
+ west update
+
+ - name: Configure AWS Credentials
+ uses: aws-actions/configure-aws-credentials@v1
+ with:
+ aws-access-key-id: ${{ secrets.FOOTPRINT_AWS_KEY_ID }}
+ aws-secret-access-key: ${{ secrets.FOOTPRINT_AWS_ACCESS_KEY }}
+ aws-region: us-east-1
+
+ - name: Record Footprint
+ env:
+ BASE_REF: ${{ github.base_ref }}
+ run: |
+ export ZEPHYR_BASE=${PWD}
+ ./scripts/footprint/track.py -p scripts/footprint/plan.txt
+ aws s3 sync --quiet footprint_data/ s3://testing.zephyrproject.org/footprint_data/
diff --git a/.github/workflows/footprint.yml b/.github/workflows/footprint.yml
new file mode 100644
index 0000000000000..ff6e32fe8da25
--- /dev/null
+++ b/.github/workflows/footprint.yml
@@ -0,0 +1,69 @@
+name: Footprint Delta
+
+on: pull_request
+
+jobs:
+ footprint-cancel:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Cancel Previous Runs
+ uses: styfle/cancel-workflow-action@0.6.0
+ with:
+ access_token: ${{ github.token }}
+ footprint-delta:
+ runs-on: ubuntu-latest
+ needs: footprint-cancel
+ container:
+ image: zephyrprojectrtos/ci:v0.17.1
+ options: '--entrypoint /bin/bash'
+ strategy:
+ fail-fast: false
+ env:
+ ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.12.4
+ CLANG_ROOT_DIR: /usr/lib/llvm-12
+ ZEPHYR_TOOLCHAIN_VARIANT: zephyr
+ steps:
+ - name: Cancel Previous Runs
+ uses: styfle/cancel-workflow-action@0.6.0
+ with:
+ access_token: ${{ github.token }}
+ - name: Update PATH for west
+ run: |
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
+
+ - name: checkout
+ uses: actions/checkout@v2
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+
+ - name: west setup
+ run: |
+ west init -l . || true
+ west update
+
+ - name: Detect Changes in Footprint
+ env:
+ BASE_REF: ${{ github.base_ref }}
+ run: |
+ export ZEPHYR_BASE=${PWD}
+ git config --global user.email "actions@zephyrproject.org"
+ git config --global user.name "Github Actions"
+ git remote -v
+ git rebase origin/${BASE_REF}
+ git checkout -b this_pr
+ west build -b frdm_k64f tests/benchmarks/footprints -t ram_report
+ cp build/ram.json ram2.json
+ west build -b frdm_k64f tests/benchmarks/footprints -t rom_report
+ cp build/rom.json rom2.json
+
+ git checkout origin/${BASE_REF}
+ west update
+ west build -p always -b frdm_k64f tests/benchmarks/footprints -t ram_report
+ west build -b frdm_k64f tests/benchmarks/footprints -t rom_report
+ cp build/ram.json ram1.json
+ cp build/rom.json rom1.json
+
+ git checkout this_pr
+ ./scripts/footprint/fpdiff.py ram1.json ram2.json
+ ./scripts/footprint/fpdiff.py rom1.json rom2.json
diff --git a/CODEOWNERS b/CODEOWNERS
index 9de40dae95d14..b020932088b6d 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -221,6 +221,7 @@
/drivers/flash/ @nashif @nvlsianpu
/drivers/flash/*nrf* @nvlsianpu
/drivers/gpio/ @mnkp
+/drivers/gpio/*b91* @yurvyn
/drivers/gpio/*lmp90xxx* @henrikbrixandersen
/drivers/gpio/*stm32* @erwango
/drivers/gpio/*eos_s3* @wtatarski @kowalewskijan @kgugala
@@ -266,6 +267,7 @@
/drivers/modem/Kconfig.hl7800 @rerickson1
/drivers/pcie/ @dcpleung @nashif @jhedberg
/drivers/peci/ @albertofloyd @franciscomunoz @scottwcpg
+/drivers/pinmux/*b91* @yurvyn
/drivers/pinmux/*hsdk* @iriszzw
/drivers/pinmux/*it8xxx2* @ite
/drivers/pm_cpu_ops/ @carlocaione
@@ -289,6 +291,7 @@
/drivers/sensor/lsm*/ @avisconti
/drivers/sensor/mpr/ @sven-hm
/drivers/sensor/st*/ @avisconti
+/drivers/serial/*b91* @yurvyn
/drivers/serial/uart_altera_jtag_hal.c @nashif
/drivers/serial/*ns16550* @dcpleung @nashif @jenmwms @aasthagr
/drivers/serial/*nrfx* @Mierunski @anangl
@@ -561,6 +564,7 @@
/scripts/coccicheck @himanshujha199640 @JuliaLawall
/scripts/coccinelle/ @himanshujha199640 @JuliaLawall
/scripts/coredump/ @dcpleung
+/scripts/footprint/ @nashif
/scripts/kconfig/ @ulfalizer
/scripts/logging/dictionary/ @dcpleung
/scripts/pylib/twister/expr_parser.py @nashif
diff --git a/README.rst b/README.rst
index dddeb60f47cac..5d6292ee71ffb 100644
--- a/README.rst
+++ b/README.rst
@@ -2,7 +2,7 @@
-
+
diff --git a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts
index a0e85217f8bda..e6b5275e80a24 100644
--- a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts
+++ b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts
@@ -71,6 +71,7 @@
compatible = "zephyr,power-state";
power-state-name = "standby";
min-residency-us = <5000>;
+ exit-latency-us = <240>;
};
};
};
diff --git a/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts b/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts
index 38cacc47c86a0..b69b8a03484c7 100644
--- a/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts
+++ b/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts
@@ -80,6 +80,7 @@
compatible = "zephyr,power-state";
power-state-name = "standby";
min-residency-us = <5000>;
+ exit-latency-us = <240>;
};
};
};
diff --git a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts
index 7c5d968529b13..61781334f94da 100644
--- a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts
+++ b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts
@@ -71,6 +71,7 @@
compatible = "zephyr,power-state";
power-state-name = "standby";
min-residency-us = <5000>;
+ exit-latency-us = <240>;
};
};
};
diff --git a/boards/arm/frdm_k64f/doc/index.rst b/boards/arm/frdm_k64f/doc/index.rst
index 18675b4ee1ccc..565956306e277 100644
--- a/boards/arm/frdm_k64f/doc/index.rst
+++ b/boards/arm/frdm_k64f/doc/index.rst
@@ -223,40 +223,40 @@ Early versions of this board have an outdated version of the OpenSDA bootloader
and require an update. Please see the `DAPLink Bootloader Update`_ page for
instructions to update from the CMSIS-DAP bootloader to the DAPLink bootloader.
-Option 1: :ref:`opensda-daplink-onboard-debug-probe` (Recommended)
-------------------------------------------------------------------
+.. tabs::
-Install the :ref:`pyocd-debug-host-tools` and make sure they are in your search
-path.
+ .. group-tab:: OpenSDA DAPLink Onboard (Recommended)
-Follow the instructions in :ref:`opensda-daplink-onboard-debug-probe` to program
-the `OpenSDA DAPLink FRDM-K64F Firmware`_.
+ Install the :ref:`pyocd-debug-host-tools` and make sure they are in your search
+ path.
-Option 2: :ref:`opensda-jlink-onboard-debug-probe`
---------------------------------------------------
+ Follow the instructions in :ref:`opensda-daplink-onboard-debug-probe` to program
+ the `OpenSDA DAPLink FRDM-K64F Firmware`_.
-Install the :ref:`jlink-debug-host-tools` and make sure they are in your search
-path.
+ .. group-tab:: OpenSDA JLink Onboard
-The version of J-Link firmware to program to the board depends on the version
-of the DAPLink bootloader. Refer to `OpenSDA Serial and Debug Adapter`_ for
-more details. On this page, change the pull-down menu for "Choose your board to
-start" to FRDM-K64F, and review the section "To update your board with OpenSDA
-applications". Note that Segger does provide an OpenSDA J-Link Board-Specific
-Firmware for this board, however it is not compatible with the DAPLink
-bootloader. After downloading the appropriate J-Link firmware, follow the
-instructions in :ref:`opensda-jlink-onboard-debug-probe` to program to the
-board.
+ Install the :ref:`jlink-debug-host-tools` and make sure they are in your search
+ path.
-Add the arguments ``-DBOARD_FLASH_RUNNER=jlink`` and
-``-DBOARD_DEBUG_RUNNER=jlink`` when you invoke ``west build`` to override the
-default runner from pyOCD to J-Link:
+ The version of J-Link firmware to program to the board depends on the version
+ of the DAPLink bootloader. Refer to `OpenSDA Serial and Debug Adapter`_ for
+ more details. On this page, change the pull-down menu for "Choose your board to
+ start" to FRDM-K64F, and review the section "To update your board with OpenSDA
+ applications". Note that Segger does provide an OpenSDA J-Link Board-Specific
+ Firmware for this board, however it is not compatible with the DAPLink
+ bootloader. After downloading the appropriate J-Link firmware, follow the
+ instructions in :ref:`opensda-jlink-onboard-debug-probe` to program to the
+ board.
-.. zephyr-app-commands::
- :zephyr-app: samples/hello_world
- :board: frdm_k64f
- :gen-args: -DBOARD_FLASH_RUNNER=jlink -DBOARD_DEBUG_RUNNER=jlink
- :goals: build
+ Add the arguments ``-DBOARD_FLASH_RUNNER=jlink`` and
+ ``-DBOARD_DEBUG_RUNNER=jlink`` when you invoke ``west build`` to override the
+ default runner from pyOCD to J-Link:
+
+ .. zephyr-app-commands::
+ :zephyr-app: samples/hello_world
+ :board: frdm_k64f
+ :gen-args: -DBOARD_FLASH_RUNNER=jlink -DBOARD_DEBUG_RUNNER=jlink
+ :goals: build
Configuring a Console
=====================
diff --git a/boards/arm/ip_k66f/linker.ld b/boards/arm/ip_k66f/linker.ld
index 9641df553e1db..b8aa54b678b6b 100644
--- a/boards/arm/ip_k66f/linker.ld
+++ b/boards/arm/ip_k66f/linker.ld
@@ -39,6 +39,7 @@ SECTION_DATA_PROLOGUE(net_if_area,,SUBALIGN(4)) \
_net_if_list_end = .; \
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) \
Z_ITERABLE_SECTION_RAM(net_if_dev, 4) \
-Z_ITERABLE_SECTION_RAM(net_l2, 4)
+Z_ITERABLE_SECTION_RAM(net_l2, 4) \
+Z_ITERABLE_SECTION_RAM(eth_bridge, 4)
#include
diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts
index 4c2bd206656d4..a9174eeb1bed0 100644
--- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts
+++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts
@@ -27,6 +27,10 @@
status = "okay";
};
+&pcr {
+ status = "okay";
+};
+
&uart1 {
status = "okay";
};
diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig
index 0bbd57f0c4e9e..f8c33a22e5944 100644
--- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig
+++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig
@@ -10,6 +10,7 @@ CONFIG_BOARD_MEC172XEVB_ASSY6906=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=96000000
+CONFIG_CLOCK_CONTROL=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
diff --git a/boards/arm/mimxrt685_evk/doc/index.rst b/boards/arm/mimxrt685_evk/doc/index.rst
index 14cab7fc1cafc..e2932da3fa206 100644
--- a/boards/arm/mimxrt685_evk/doc/index.rst
+++ b/boards/arm/mimxrt685_evk/doc/index.rst
@@ -184,24 +184,28 @@ Configuring a Debug Probe
A debug probe is used for both flashing and debugging the board. This board is
configured by default to use the LPC-Link2.
-:ref:`lpclink2-jlink-onboard-debug-probe`
------------------------------------------
+.. tabs::
-Install the :ref:`jlink-debug-host-tools` and make sure they are in your search
-path. Install jumpers JP17, JP18 and JP19, to connect the SWD signals from onboard
-debug circuit. These jumpers are installed by default.
+ .. group-tab:: LPCLink2 JLink Onboard
-Follow the instructions in :ref:`lpclink2-jlink-onboard-debug-probe` to program
-the J-Link firmware. Please make sure you have the latest firmware for this
-board.
-:ref:`jlink-external-debug-probe`
------------------------------------------
+ 1. Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path.
+ 2. To connect the SWD signals to onboard debug circuit, install jumpers JP17, JP18 and JP19,
+ if not already done (these jumpers are installed by default).
+ 3. Follow the instructions in :ref:`lpclink2-jlink-onboard-debug-probe` to program the
+ J-Link firmware. Please make sure you have the latest firmware for this board.
-Install the :ref:`jlink-debug-host-tools` and make sure they are in your search
-path. Remove jumpers JP17, JP18 and JP19, to disconnect the SWD signals from onboard
-debug circuit. These jumpers are installed by default. Connect the J-Link probe
-to J2 10-pin header.
+ .. group-tab:: JLink External
+
+
+ 1. Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path.
+
+ 2. To disconnect the SWD signals from onboard debug circuit, **remove** jumpers J17, J18,
+ and J19 (these are installed by default).
+
+ 3. Connect the J-Link probe to J2 10-pin header.
+
+ See :ref:`jlink-external-debug-probe` for more information.
Configuring a Console
=====================
diff --git a/boards/posix/native_posix/Kconfig.defconfig b/boards/posix/native_posix/Kconfig.defconfig
index a226c26d60310..160ccad25b416 100644
--- a/boards/posix/native_posix/Kconfig.defconfig
+++ b/boards/posix/native_posix/Kconfig.defconfig
@@ -23,6 +23,9 @@ config NET_L2_ETHERNET
config ETH_NATIVE_POSIX
default y if NET_L2_ETHERNET
+config CAN_NATIVE_POSIX
+ default y if NET_SOCKETS_CAN
+
endif # NETWORKING
config FAKE_ENTROPY_NATIVE_POSIX
diff --git a/boards/posix/native_posix/native_posix.dts b/boards/posix/native_posix/native_posix.dts
index 5e52d3cbca163..28995c8ffaf01 100644
--- a/boards/posix/native_posix/native_posix.dts
+++ b/boards/posix/native_posix/native_posix.dts
@@ -141,6 +141,26 @@
current-speed = <0>;
};
+ can1: can_1 {
+ status = "okay";
+ compatible = "zephyr,native-posix-can";
+ label = "CAN_1";
+ /* Dummy bus-speed entry to comply with can
+ * DTS binding
+ */
+ bus-speed = <500000>;
+ };
+
+ can2: can_2 {
+ status = "okay";
+ compatible = "zephyr,native-posix-can";
+ label = "CAN_2";
+ /* Dummy bus-speed entry to comply with can
+ * DTS binding
+ */
+ bus-speed = <500000>;
+ };
+
rng: rng {
status = "okay";
compatible = "zephyr,native-posix-rng";
diff --git a/boards/riscv/tlsr9518adk80d/Kconfig.board b/boards/riscv/tlsr9518adk80d/Kconfig.board
new file mode 100644
index 0000000000000..bd36cb0e481f3
--- /dev/null
+++ b/boards/riscv/tlsr9518adk80d/Kconfig.board
@@ -0,0 +1,6 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+config BOARD_TLSR9518ADK80D
+ bool "Telink B91 Platform"
+ depends on SOC_RISCV_TELINK_B91
diff --git a/boards/riscv/tlsr9518adk80d/Kconfig.defconfig b/boards/riscv/tlsr9518adk80d/Kconfig.defconfig
new file mode 100644
index 0000000000000..2b3208b03d1aa
--- /dev/null
+++ b/boards/riscv/tlsr9518adk80d/Kconfig.defconfig
@@ -0,0 +1,21 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+if BOARD_TLSR9518ADK80D
+
+config BOARD
+ default "tlsr9518adk80d"
+
+config COMPRESSED_ISA
+ default y
+
+config GPIO_TELINK_B91
+ default y if GPIO
+
+config UART_TELINK_B91
+ default y if SERIAL
+
+config PINMUX_TELINK_B91
+ default y if PINMUX
+
+endif
diff --git a/boards/riscv/tlsr9518adk80d/doc/img/tlsr9518_block_diagram.jpg b/boards/riscv/tlsr9518adk80d/doc/img/tlsr9518_block_diagram.jpg
new file mode 100644
index 0000000000000..2b0b2818ed3fb
Binary files /dev/null and b/boards/riscv/tlsr9518adk80d/doc/img/tlsr9518_block_diagram.jpg differ
diff --git a/boards/riscv/tlsr9518adk80d/doc/img/tlsr9518adk80d.jpg b/boards/riscv/tlsr9518adk80d/doc/img/tlsr9518adk80d.jpg
new file mode 100644
index 0000000000000..76f34a9dc9c36
Binary files /dev/null and b/boards/riscv/tlsr9518adk80d/doc/img/tlsr9518adk80d.jpg differ
diff --git a/boards/riscv/tlsr9518adk80d/doc/index.rst b/boards/riscv/tlsr9518adk80d/doc/index.rst
new file mode 100644
index 0000000000000..8f54ed0df5bed
--- /dev/null
+++ b/boards/riscv/tlsr9518adk80d/doc/index.rst
@@ -0,0 +1,208 @@
+.. _tlst9518adk80d:
+
+Telink TLSR9518ADK80D
+#####################
+
+Overview
+********
+
+The TLSR9518A Generic Starter Kit is a hardware platform which
+can be used to verify the `Telink TLSR9 series chipset`_ and develop applications
+for several 2.4 GHz air interface standards including Bluetooth 5.2 (Basic data
+rate, Enhanced data rate, LE, Indoor positioning and BLE Mesh),
+Zigbee 3.0, Homekit, 6LoWPAN, Thread and 2.4 Ghz proprietary.
+
+.. figure:: img/tlsr9518adk80d.jpg
+ :width: 400px
+ :align: center
+ :alt: TLSR9518ADK80D
+
+More information about the board can be found at the `Telink B91 Generic Starter Kit Hardware Guide`_ website.
+
+Hardware
+********
+
+The TLSR9518A SoC integrates a powerful 32-bit RISC-V MCU, DSP, AI Engine, 2.4 GHz ISM Radio, 256
+KB SRAM (128 KB of Data Local Memory and 128 KB of Instruction Local Memory), external Flash memory,
+stereo audio codec, 14 bit AUX ADC, analog and digital Microphone input, PWM, flexible IO interfaces,
+and other peripheral blocks required for advanced IoT, hearable, and wearable devices.
+
+.. figure:: img/tlsr9518_block_diagram.jpg
+ :width: 400px
+ :align: center
+ :alt: TLSR9518ADK80D_SOC
+
+The TLSR9518ADK80D default board configuration provides the following hardware components:
+
+- RF conducted antenna
+- 1 MB External Flash memory with reset button
+- Chip reset button
+- Mini USB interface
+- 4-wire JTAG
+- 4 LEDs, Key matrix up to 4 keys
+- 2 line-in function (Dual Analog microphone supported when switching jumper from microphone path)
+- Dual Digital microphone
+- Stereo line-out
+
+Supported Features
+==================
+
+The Zephyr TLSR9518ADK80D board configuration supports the following hardware features:
+
++----------------+------------+------------------------------+
+| Interface | Controller | Driver/Component |
++================+============+==============================+
+| PLIC | on-chip | interrupt_controller |
++----------------+------------+------------------------------+
+| RISC-V Machine | on-chip | timer |
+| Timer (32 KHz) | | |
++----------------+------------+------------------------------+
+| PINMUX | on-chip | pinmux |
++----------------+------------+------------------------------+
+| GPIO | on-chip | gpio |
++----------------+------------+------------------------------+
+| UART | on-chip | serial |
++----------------+------------+------------------------------+
+
+The following example projects are supported:
+
+- samples/hello_world
+- samples/synchronization
+- samples/philosophers
+- samples/basic/threads
+- samples/basic/blinky
+- samples/basic/button
+- samples/subsys/console/echo
+- samples/subsys/console/getchar
+- samples/subsys/console/getline
+- samples/subsys/shell/shell_module
+- samples/subsys/cpp/cpp_synchronization
+
+.. note::
+ To support "button" example project PC3-KEY3 (J20-19, J20-20) jumper needs to be removed and KEY3 (J20-19) should be connected to VDD3_DCDC (J51-13) externally.
+
+ For the rest example projects use the default jumpers configuration.
+
+Other hardware features and example projects are not supported yet.
+
+Limitations
+-----------
+
+- Maximum 3 GPIO pins could be configured to generate interrupts simultaneously. All pins must be related to different ports and use different IRQ numbers.
+- DMA mode is not supported by Serial Port.
+- UART hardware flow control is not implemented.
+
+Default configuration and IOs
+=============================
+
+System Clock
+------------
+
+The TLSR9518ADK80D board is configured to use the 24 MHz external crystal oscillator
+with the on-chip PLL/DIV generating the 48 MHz system clock.
+The following values also could be assigned to the system clock in the board DTS file
+(``boards/riscv/tlsr9518adk80d/tlsr9518adk80d.dts``):
+
+- 16000000
+- 24000000
+- 32000000
+- 48000000
+- 64000000
+- 96000000
+
+.. code-block::
+
+ &cpu0 {
+ clock-frequency = <48000000>;
+ };
+
+PINs Configuration
+------------------
+
+The TLSR9518A SoC has five GPIO controllers (PORT_A to PORT_E), but only two are
+currently enabled (PORT_B for LEDs control and PORT_C for buttons) in the board DTS file:
+
+- LED0 (blue): PB4, LED1 (green): PB5, LED2 (white): PB6, LED3 (red): PB7
+- Key Matrix SW0: PC2_PC3, SW1: PC2_PC1, SW2: PC0_PC3, SW3: PC0_PC1
+
+Peripheral's pins on the SoC are mapped to the following GPIO pins in the
+``boards/riscv/tlsr9518adk80d/tlsr9518adk80d.dts`` file:
+
+- UART0 RX: PB2, TX: PB3
+- UART1 RX: PC6, TX: PC7
+
+Serial Port
+-----------
+
+The TLSR9518A SoC has 2 UARTs. The Zephyr console output is assigned
+to UART0 in the ``boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig`` file.
+The default settings are 115200 8N1.
+
+Programming and debugging
+*************************
+
+Building
+========
+
+You can build applications in the usual way. Here is an example for
+the "hello_world" application.
+
+.. code-block:: console
+
+ # From the root of the zephyr repository
+ west build -b tlsr9518adk80d samples/hello_world
+
+To use `Telink RISC-V Linux Toolchain`_, ``ZEPHYR_TOOLCHAIN_VARIANT`` and ``CROSS_COMPILE`` variables need to be set.
+
+.. code-block:: console
+
+ # Set Zephyr toolchain variant to cross-compile
+ export ZEPHYR_TOOLCHAIN_VARIANT=cross-compile
+ # Specify the Telink RISC-V Toolchain location
+ export CROSS_COMPILE=~/toolchains/nds32le-elf-mculib-v5f/bin/riscv32-elf-
+ # From the root of the zephyr repository
+ west build -b tlsr9518adk80d samples/hello_world
+
+`Telink RISC-V Linux Toolchain`_ is available on the `Burning and Debugging Tools for TLSR9 Series in Linux`_ page.
+
+Open a serial terminal with the following settings:
+
+- Speed: 115200
+- Data: 8 bits
+- Parity: None
+- Stop bits: 1
+
+Flash the board, reset and observe the following messages on the selected
+serial port:
+
+.. code-block:: console
+
+ *** Booting Zephyr OS version 2.5.0 ***
+ Hello World! tlsr9518adk80d
+
+
+Flashing
+========
+
+In order to flash the TLSR9518ADK80D board check the following resources:
+
+- `Burning and Debugging Tools for all Series`_
+- `Burning and Debugging Tools for TLSR9 Series`_
+- `Burning and Debugging Tools for TLSR9 Series in Linux`_
+
+Debugging
+=========
+
+Supporting UART debug and OpenOCD+GDB.
+
+References
+**********
+
+.. target-notes::
+
+.. _Telink TLSR9 series chipset: http://wiki.telink-semi.cn/wiki/chip-series/TLSR9-Series/
+.. _Telink B91 Generic Starter Kit Hardware Guide: http://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/
+.. _Telink RISC-V Linux Toolchain: http://wiki.telink-semi.cn/tools_and_sdk/Tools/IDE/telink_riscv_linux_toolchain.zip
+.. _Burning and Debugging Tools for all Series: http://wiki.telink-semi.cn/wiki/IDE-and-Tools/Burning-and-Debugging-Tools-for-all-Series/
+.. _Burning and Debugging Tools for TLSR9 Series: http://wiki.telink-semi.cn/wiki/IDE-and-Tools/Burning-and-Debugging-Tools-for-TLSR9-Series/
+.. _Burning and Debugging Tools for TLSR9 Series in Linux: http://wiki.telink-semi.cn/wiki/IDE-and-Tools/BDT_for_TLSR9_Series_in_Linux/
diff --git a/boards/riscv/tlsr9518adk80d/tlsr9518adk80d.dts b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d.dts
new file mode 100644
index 0000000000000..82bee5e59e0db
--- /dev/null
+++ b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d.dts
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/dts-v1/;
+
+#include
+
+/ {
+ model = "telink,b91";
+ compatible = "telink,tlsr9518adk80d";
+
+ aliases {
+ led0 = &led_blue;
+ led1 = &led_green;
+ sw0 = &key_1;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led_blue: led_0 {
+ gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>;
+ label = "LED Blue";
+ };
+
+ led_green: led_1 {
+ gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>;
+ label = "LED Green";
+ };
+
+ led_white: led_2 {
+ gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>;
+ label = "LED White";
+ };
+
+ led_red: led_3 {
+ gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>;
+ label = "LED Red";
+ };
+ };
+
+ keys {
+ compatible = "gpio-keys";
+ key_1: button_1 {
+ label = "User KEY1";
+ gpios = <&gpioc 2 GPIO_PULL_DOWN>;
+ };
+ };
+
+ chosen {
+ zephyr,console = &uart0;
+ zephyr,shell-uart = &uart0;
+ zephyr,sram = &ram_dlm;
+ zephyr,flash = &flash;
+ zephyr,flash-controller = &flash_mspi;
+ };
+};
+
+&cpu0 {
+ clock-frequency = <48000000>;
+};
+
+&ram_ilm {
+ reg = <0x00000000 0x00020000>;
+};
+
+&ram_dlm {
+ reg = <0x00080000 0x00020000>;
+};
+
+&flash {
+ reg = <0x20000000 0x100000>;
+};
+
+&gpiob {
+ status = "okay";
+};
+
+&gpioc {
+ interrupts = <25 1>;
+ status = "okay";
+};
+
+&pinmux {
+ status = "okay";
+ pad-mul-sel = <1>;
+};
+
+&uart0 {
+ status = "okay";
+ current-speed = <115200>;
+ pinctrl-0 = <&uart0_tx_pb2 &uart0_rx_pb3>;
+};
+
+&flash_mspi {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ boot_partition: partition@0 {
+ label = "mcuboot";
+ reg = <0x00000000 0x8000>;
+ };
+ slot0_partition: partition@8000 {
+ label = "image-0";
+ reg = <0x00008000 0x1a000>;
+ };
+ slot1_partition: partition@22000 {
+ label = "image-1";
+ reg = <0x00022000 0x1a000>;
+ };
+ scratch_partition: partition@3c000 {
+ label = "image-scratch";
+ reg = <0x0003c000 0x2000>;
+ };
+ storage_partition: partition@f0000 {
+ label = "storage";
+ reg = <0x000f0000 0x00010000>;
+ };
+ };
+};
diff --git a/boards/riscv/tlsr9518adk80d/tlsr9518adk80d.yaml b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d.yaml
new file mode 100644
index 0000000000000..e661002a9ef40
--- /dev/null
+++ b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d.yaml
@@ -0,0 +1,11 @@
+identifier: tlsr9518adk80d
+name: Telink TLSR9518ADK80D
+type: mcu
+arch: riscv32
+toolchain:
+ - cross-compile
+ - zephyr
+ram: 128
+flash: 1024
+supported:
+ - gpio
diff --git a/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig
new file mode 100644
index 0000000000000..0ed61f5764367
--- /dev/null
+++ b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig
@@ -0,0 +1,17 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+CONFIG_SOC_SERIES_RISCV_TELINK_B91=y
+CONFIG_SOC_RISCV_TELINK_B91=y
+CONFIG_BOARD_TLSR9518ADK80D=y
+CONFIG_PLIC=y
+CONFIG_RISCV_MACHINE_TIMER=y
+CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000
+CONFIG_PINMUX=y
+CONFIG_UART_INTERRUPT_DRIVEN=y
+CONFIG_SERIAL=y
+CONFIG_CONSOLE=y
+CONFIG_UART_CONSOLE=y
+
+# HW DSP options
+CONFIG_TELINK_B91_HWDSP=n
diff --git a/cmake/linker/arcmwdt/target.cmake b/cmake/linker/arcmwdt/target.cmake
index 6b49a0c966eed..1db1f6f307bbc 100644
--- a/cmake/linker/arcmwdt/target.cmake
+++ b/cmake/linker/arcmwdt/target.cmake
@@ -35,6 +35,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
OUTPUT ${linker_script_gen}
DEPENDS
${LINKER_SCRIPT}
+ ${AUTOCONF_H}
${extra_dependencies}
# NB: 'linker_script_dep' will use a keyword that ends 'DEPENDS'
${linker_script_dep}
@@ -45,6 +46,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
-MD -MF ${linker_script_gen}.dep -MT ${base_name}/${linker_script_gen}
-D_LINKER
-D_ASMLANGUAGE
+ -imacros ${AUTOCONF_H}
${current_includes}
${current_defines}
${linker_pass_define}
diff --git a/cmake/linker/ld/target.cmake b/cmake/linker/ld/target.cmake
index ba790789f195c..571964fcbe934 100644
--- a/cmake/linker/ld/target.cmake
+++ b/cmake/linker/ld/target.cmake
@@ -54,6 +54,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
OUTPUT ${linker_script_gen}
DEPENDS
${LINKER_SCRIPT}
+ ${AUTOCONF_H}
${extra_dependencies}
# NB: 'linker_script_dep' will use a keyword that ends 'DEPENDS'
${linker_script_dep}
@@ -63,6 +64,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
-MD -MF ${linker_script_gen}.dep -MT ${base_name}/${linker_script_gen}
-D_LINKER
-D_ASMLANGUAGE
+ -imacros ${AUTOCONF_H}
${current_includes}
${current_defines}
${linker_pass_define}
diff --git a/cmake/reports/CMakeLists.txt b/cmake/reports/CMakeLists.txt
index 4749e8f744668..7dc3ef2181ff6 100644
--- a/cmake/reports/CMakeLists.txt
+++ b/cmake/reports/CMakeLists.txt
@@ -2,6 +2,7 @@
set(flag_for_ram_report ram)
set(flag_for_rom_report rom)
+set(flag_for_footprint all -q)
set(report_depth 99)
if(DEFINED ZEPHYR_WORKSPACE)
@@ -10,7 +11,7 @@ elseif(DEFINED WEST_TOPDIR)
set(workspace_arg "--workspace=${WEST_TOPDIR}")
endif()
-foreach(report ram_report rom_report)
+foreach(report ram_report rom_report footprint)
add_custom_target(
${report}
${PYTHON_EXECUTABLE}
@@ -19,12 +20,12 @@ foreach(report ram_report rom_report)
-z ${ZEPHYR_BASE}
-o ${CMAKE_BINARY_DIR}
${workspace_arg}
- --json ${CMAKE_BINARY_DIR}/${flag_for_${report}}.json
-d ${report_depth}
${flag_for_${report}}
DEPENDS ${logical_target_for_zephyr_elf}
$
USES_TERMINAL
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endforeach()
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index e7b1c8a91bc65..5f97f337b2d1c 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -45,8 +45,6 @@ find_program(WEST west)
# Environment & Paths
set(SPHINX_ENV
- ZEPHYR_BASE=${ZEPHYR_BASE}
- ZEPHYR_BUILD=${CMAKE_CURRENT_BINARY_DIR}
DOXYGEN_EXECUTABLE=${DOXYGEN_EXECUTABLE}
DOT_EXECUTABLE=${DOXYGEN_DOT_EXECUTABLE}
)
diff --git a/doc/_static/images/logo-readme.png b/doc/_static/images/logo-readme.png
new file mode 100644
index 0000000000000..0fb6e008f6bfd
Binary files /dev/null and b/doc/_static/images/logo-readme.png differ
diff --git a/doc/conf.py b/doc/conf.py
index 721464aa53ba1..47be5fd1047c6 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -6,18 +6,13 @@
from pathlib import Path
import re
+from sphinx.cmd.build import get_parser
import sphinx_rtd_theme
-ZEPHYR_BASE = os.environ.get("ZEPHYR_BASE")
-if not ZEPHYR_BASE:
- raise ValueError("ZEPHYR_BASE environment variable undefined")
-ZEPHYR_BASE = Path(ZEPHYR_BASE)
-
-ZEPHYR_BUILD = os.environ.get("ZEPHYR_BUILD")
-if not ZEPHYR_BUILD:
- raise ValueError("ZEPHYR_BUILD environment variable undefined")
-ZEPHYR_BUILD = Path(ZEPHYR_BUILD)
+args = get_parser().parse_args()
+ZEPHYR_BASE = Path(__file__).resolve().parents[1]
+ZEPHYR_BUILD = Path(args.outputdir).resolve()
# Add the '_extensions' directory to sys.path, to enable finding Sphinx
# extensions within.
diff --git a/doc/contribute/coding_guidelines/index.rst b/doc/contribute/coding_guidelines/index.rst
index 9bec8abf8c951..76982e5574d63 100644
--- a/doc/contribute/coding_guidelines/index.rst
+++ b/doc/contribute/coding_guidelines/index.rst
@@ -706,51 +706,6 @@ severity and the equivlent rules from other standards for reference.
- The library functions bsearch and qsort of shall not be used
- N/A
- `Rule 21.9 `_
- * - Rule 22.1
- - Required
- - All resources obtained dynamically by means of Standard Library functions shall be explicitly released
- - N/A
- - `Rule 22.1 `_
- * - Rule 22.3
- - Required
- - The same file shall not be open for read and write access at the same time on different streams
- - N/A
- - `Rule 22.3 `_
- * - Rule 22.4
- - Mandatory
- - There shall be no attempt to write to a stream which has been opened as read-only
- - N/A
- - `Rule 22.4 `_
- * - Rule 22.5
- - Mandatory
- - A pointer to a FILE object shall not be dereferenced
- - N/A
- - `Rule 22.5 `_
- * - Rule 22.6
- - Mandatory
- - The value of a pointer to a FILE shall not be used after the associated stream has been closed
- - N/A
- - `Rule 22.6 `_
- * - Rule 22.7
- - Required
- - The macro EOF shall only be compared with the unmodified return value from any Standard Library function capable of returning EOF
- - N/A
- - `Rule 22.7 `_
- * - Rule 22.8
- - Required
- - The value of errno shall be set to zero prior to a call to an errno-setting-function
- - N/A
- - `Rule 22.8 `_
- * - Rule 22.9
- - Required
- - The value of errno shall be tested against zero after calling an errno-setting-function
- - N/A
- - `Rule 22.9 `_
- * - Rule 22.10
- - Required
- - The value of errno shall only be tested when the last function to be called was an errno-setting-function
- - N/A
- - `Rule 22.10 `_
* - Rule 21.11
- Required
- The standard header file shall not be used
@@ -796,6 +751,51 @@ severity and the equivlent rules from other standards for reference.
- The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function
- N/A
- `Rule 21.20 `_
+ * - Rule 22.1
+ - Required
+ - All resources obtained dynamically by means of Standard Library functions shall be explicitly released
+ - N/A
+ - `Rule 22.1 `_
+ * - Rule 22.3
+ - Required
+ - The same file shall not be open for read and write access at the same time on different streams
+ - N/A
+ - `Rule 22.3 `_
+ * - Rule 22.4
+ - Mandatory
+ - There shall be no attempt to write to a stream which has been opened as read-only
+ - N/A
+ - `Rule 22.4 `_
+ * - Rule 22.5
+ - Mandatory
+ - A pointer to a FILE object shall not be dereferenced
+ - N/A
+ - `Rule 22.5 `_
+ * - Rule 22.6
+ - Mandatory
+ - The value of a pointer to a FILE shall not be used after the associated stream has been closed
+ - N/A
+ - `Rule 22.6 `_
+ * - Rule 22.7
+ - Required
+ - The macro EOF shall only be compared with the unmodified return value from any Standard Library function capable of returning EOF
+ - N/A
+ - `Rule 22.7 `_
+ * - Rule 22.8
+ - Required
+ - The value of errno shall be set to zero prior to a call to an errno-setting-function
+ - N/A
+ - `Rule 22.8 `_
+ * - Rule 22.9
+ - Required
+ - The value of errno shall be tested against zero after calling an errno-setting-function
+ - N/A
+ - `Rule 22.9 `_
+ * - Rule 22.10
+ - Required
+ - The value of errno shall only be tested when the last function to be called was an errno-setting-function
+ - N/A
+ - `Rule 22.10 `_
Additional rules
****************
diff --git a/doc/getting_started/index.rst b/doc/getting_started/index.rst
index f4ebfc99f9f30..a35841c89b29d 100644
--- a/doc/getting_started/index.rst
+++ b/doc/getting_started/index.rst
@@ -649,6 +649,6 @@ search the archives.
When copy/pasting more than 5 lines of text into Slack, create a `snippet`_.
.. _Search archives and sign up here: https://lists.zephyrproject.org/g/users
-.. _Slack invite: https://tinyurl.com/y5glwylp
+.. _Slack invite: https://tinyurl.com/2vue8666
.. _GitHub issues: https://github.com/zephyrproject-rtos/zephyr/issues
.. _snippet: https://get.slack.help/hc/en-us/articles/204145658-Create-a-snippet
diff --git a/doc/reference/peripherals/espi.rst b/doc/reference/peripherals/espi.rst
new file mode 100644
index 0000000000000..5a9d0871e2e93
--- /dev/null
+++ b/doc/reference/peripherals/espi.rst
@@ -0,0 +1,27 @@
+.. _espi_api:
+
+eSPI
+####
+
+Overview
+********
+
+The eSPI (enhanced serial peripheral interface) is a serial bus that is
+based on SPI. It also features a four-wire interface (receive, transmit, clock
+and slave select) and three configurations: single IO, dual IO and quad IO.
+
+The technical advancements include lower voltage signal levels (1.8V vs. 3.3V),
+lower pin count, and the frequency is twice as fast (66MHz vs. 33MHz)
+Because of its enhancements, the eSPI is used to replace the LPC
+(lower pin count) interface, SPI, SMBus and sideband signals.
+
+See `eSPI interface specification`_ for additional details.
+
+
+API Reference
+*************
+
+.. doxygengroup:: espi_interface
+
+.. _eSPI interface specification:
+ https://www.intel.com/content/dam/support/us/en/documents/software/chipset-software/327432-004_espi_base_specification_rev1.0_cb.pdf
diff --git a/doc/reference/peripherals/index.rst b/doc/reference/peripherals/index.rst
index 1c2b81e83b298..2e6ed3f46e22a 100644
--- a/doc/reference/peripherals/index.rst
+++ b/doc/reference/peripherals/index.rst
@@ -34,3 +34,4 @@ Peripherals
uart.rst
watchdog.rst
video.rst
+ espi.rst
diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt
index 8276094bd737e..cbd130e5b1761 100644
--- a/drivers/can/CMakeLists.txt
+++ b/drivers/can/CMakeLists.txt
@@ -12,3 +12,15 @@ zephyr_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c)
zephyr_sources_ifdef(CONFIG_USERSPACE can_handlers.c)
zephyr_sources_ifdef(CONFIG_CAN_SHELL can_shell.c)
zephyr_sources_ifdef(CONFIG_CAN_NET can_net.c)
+
+if(CONFIG_CAN_NATIVE_POSIX)
+ zephyr_library()
+ zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2)
+ zephyr_library_compile_definitions(NO_POSIX_CHEATS)
+ zephyr_library_compile_definitions(_BSD_SOURCE)
+ zephyr_library_compile_definitions(_DEFAULT_SOURCE)
+ zephyr_library_sources(
+ can_native_posix.c
+ can_native_posix_adapt.c
+ )
+endif()
diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig
index ba975e9640bdf..219282694d314 100644
--- a/drivers/can/Kconfig
+++ b/drivers/can/Kconfig
@@ -94,5 +94,6 @@ source "drivers/can/Kconfig.mcan"
source "drivers/can/Kconfig.rcar"
source "drivers/can/Kconfig.loopback"
source "drivers/can/Kconfig.net"
+source "drivers/can/Kconfig.native_posix"
endif # CAN
diff --git a/drivers/can/Kconfig.native_posix b/drivers/can/Kconfig.native_posix
new file mode 100644
index 0000000000000..5b8ae430c19a9
--- /dev/null
+++ b/drivers/can/Kconfig.native_posix
@@ -0,0 +1,71 @@
+# Native posix CAN configuration options
+
+# Copyright (c) 2019 Intel Corporation
+# SPDX-License-Identifier: Apache-2.0
+
+config CAN_NATIVE_POSIX
+ bool "native_posix CAN Driver"
+ depends on ARCH_POSIX && NETWORKING
+ help
+ Enable native_posix CAN driver
+
+if CAN_NATIVE_POSIX
+
+config CAN_MAX_FILTER
+ int "Maximum number of concurrent active filters"
+ depends on CAN_NATIVE_POSIX
+ default 32
+ range 1 56
+ help
+ Defines the array size of the callback/msgq pointers.
+ Must be at least the size of concurrent reads.
+
+## Interface 1
+config CAN_NATIVE_POSIX_INTERFACE_1_ENABLED
+ bool "CANBUS interface 1"
+ default y
+ depends on CAN_NATIVE_POSIX
+ help
+ This option enables the CANBUS network interface for Native POSIX board.
+
+config CAN_NATIVE_POSIX_INTERFACE_1_NAME
+ string "CANBUS interface 1 name on Linux side"
+ depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLED
+ default "vcan0"
+ help
+ This option sets the CANBUS network interface 1 name in host system.
+
+config CAN_NATIVE_POSIX_INTERFACE_1_SOCKETCAN_NAME
+ string "Network device name"
+ depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLED
+ default "SOCKET_CAN_1"
+ help
+ Name of the network device driver for SocketCAN.
+
+## Interface 2
+config CAN_NATIVE_POSIX_INTERFACE_2_ENABLED
+ bool "CANBUS interface 2"
+ default n
+ depends on CAN_NATIVE_POSIX
+ help
+ This option enables the CANBUS network interface for Native POSIX board.
+
+if CAN_NATIVE_POSIX_INTERFACE_2_ENABLED
+
+config CAN_NATIVE_POSIX_INTERFACE_2_NAME
+ string "CANBUS interface 2 name on Linux side"
+ depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLED
+ default "vcan1"
+ help
+ This option sets the CANBUS network interface 2 name in host system.
+
+config CAN_NATIVE_POSIX_INTERFACE_2_SOCKETCAN_NAME
+ string "Network device name"
+ depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLED
+ default "SOCKET_CAN_2"
+ help
+ Name of the network device driver for SocketCAN.
+
+endif #CAN_NATIVE_POSIX_INTERFACE_2_ENABLED
+
+endif #CAN_NATIVE_POSIX
diff --git a/drivers/can/can_native_posix.c b/drivers/can/can_native_posix.c
new file mode 100644
index 0000000000000..398abf8580d79
--- /dev/null
+++ b/drivers/can/can_native_posix.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2019 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ *
+ * CANBUS driver for native_posix board. This is meant to test CANBUS
+ * connectivity between host and Zephyr.
+ */
+
+#define DT_DRV_COMPAT zephyr_native_posix_can
+
+#define LOG_MODULE_NAME canbus_posix
+#define LOG_LEVEL CONFIG_CAN_LOG_LEVEL
+
+#include
+LOG_MODULE_REGISTER(LOG_MODULE_NAME);
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "can_native_posix_priv.h"
+#include "socket_can_context.h"
+
+#define NET_BUF_TIMEOUT K_MSEC(100)
+
+static int read_data(struct socket_can_context *ctx, int fd)
+{
+ struct net_pkt *pkt;
+ int count;
+
+ struct can_frame frame;
+
+ count = canbus_np_read_data(fd, (void *)(&frame), sizeof(frame));
+
+ if (count <= 0) {
+ return 0;
+ }
+
+ struct zcan_frame zframe;
+
+ can_copy_frame_to_zframe(&frame, &zframe);
+
+ pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, sizeof(zframe), AF_CAN,
+ 0, NET_BUF_TIMEOUT);
+ if (!pkt) {
+ return -ENOMEM;
+ }
+
+ if (net_pkt_write(pkt, (void *)(&zframe), sizeof(zframe))) {
+ net_pkt_unref(pkt);
+ return -ENOBUFS;
+ }
+
+ if (net_recv_data(ctx->iface, pkt) < 0) {
+ net_pkt_unref(pkt);
+ }
+
+ return 0;
+}
+
+static void canbus_np_rx(struct socket_can_context *ctx)
+{
+ LOG_DBG("Starting ZCAN RX thread");
+
+ while (1) {
+ if (ctx->iface && net_if_is_up(ctx->iface)) {
+ while (!canbus_np_wait_data(ctx->dev_fd)) {
+ read_data(ctx, ctx->dev_fd);
+ }
+ }
+
+ k_sleep(K_MSEC(10));
+ }
+}
+
+static int canbus_np_send(const struct device *dev,
+ const struct zcan_frame *msg, k_timeout_t timeout,
+ can_tx_callback_t callback_isr, void *callback_arg)
+{
+ struct socket_can_context *ctx = dev->data;
+ int ret = -ENODEV;
+
+ ARG_UNUSED(timeout);
+ ARG_UNUSED(callback_isr);
+ ARG_UNUSED(callback_arg);
+
+ if (ctx->dev_fd > 0) {
+ struct can_frame frame;
+
+ can_copy_zframe_to_frame(msg, &frame);
+
+ ret = canbus_np_write_data(ctx->dev_fd, &frame, sizeof(frame));
+ if (ret < 0) {
+ LOG_ERR("Cannot send CAN data len %d (%d)",
+ frame.can_dlc, -errno);
+ }
+ }
+
+ return ret < 0 ? ret : 0;
+}
+
+static int canbus_np_attach_isr(const struct device *dev, can_rx_callback_t isr,
+ void *callback_arg,
+ const struct zcan_filter *filter)
+{
+ ARG_UNUSED(dev);
+ ARG_UNUSED(isr);
+ ARG_UNUSED(callback_arg);
+ ARG_UNUSED(filter);
+
+ return 0;
+}
+
+static void canbus_np_detach(const struct device *dev, int filter_nr)
+{
+ ARG_UNUSED(dev);
+ ARG_UNUSED(filter_nr);
+}
+
+enum can_state canbus_np_get_state(const struct device *dev,
+ struct can_bus_err_cnt *err_cnt)
+{
+ ARG_UNUSED(dev);
+ ARG_UNUSED(err_cnt);
+ return CAN_ERROR_ACTIVE;
+}
+
+void canbus_np_register_state_change_isr(const struct device *dev,
+ can_state_change_isr_t isr)
+{
+ ARG_UNUSED(dev);
+ ARG_UNUSED(isr);
+}
+
+static const struct can_driver_api can_api_funcs = {
+ .send = canbus_np_send,
+ .attach_isr = canbus_np_attach_isr,
+ .detach = canbus_np_detach,
+ .get_state = canbus_np_get_state,
+ .register_state_change_isr = canbus_np_register_state_change_isr
+};
+
+#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED
+K_KERNEL_STACK_DEFINE(canbus_rx_stack1,
+ CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
+static struct k_thread rx_thread_data1;
+static struct socket_can_context canbus_context_data1;
+
+static int canbus_np1_init(const struct device *dev)
+{
+ struct socket_can_context *ctx = dev->data;
+
+ ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_NAME;
+
+ ctx->dev_fd = canbus_np_iface_open(ctx->if_name);
+ if (ctx->dev_fd < 0) {
+ LOG_ERR("Cannot open %s (%d)", ctx->if_name, ctx->dev_fd);
+ } else {
+ /* Create a thread that will handle incoming data from host */
+ k_thread_create(&rx_thread_data1, canbus_rx_stack1,
+ K_THREAD_STACK_SIZEOF(canbus_rx_stack1),
+ (k_thread_entry_t)canbus_np_rx, ctx, NULL, NULL,
+ K_PRIO_PREEMPT(14), 0, K_NO_WAIT);
+ }
+
+ return 0;
+}
+
+DEVICE_DT_INST_DEFINE(0, &canbus_np1_init, NULL,
+ (void *)&canbus_context_data1, NULL,
+ POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
+ &can_api_funcs);
+#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED */
+
+#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED
+K_KERNEL_STACK_DEFINE(canbus_rx_stack2,
+ CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
+static struct k_thread rx_thread_data2;
+static struct socket_can_context canbus_context_data2;
+
+static int canbus_np2_init(const struct device *dev)
+{
+ struct socket_can_context *ctx = dev->data;
+
+ ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_NAME;
+
+ ctx->dev_fd = canbus_np_iface_open(ctx->if_name);
+ if (ctx->dev_fd < 0) {
+ LOG_ERR("Cannot open %s (%d)", ctx->if_name, ctx->dev_fd);
+ } else {
+ /* Create a thread that will handle incoming data from host */
+ k_thread_create(&rx_thread_data2, canbus_rx_stack2,
+ K_THREAD_STACK_SIZEOF(canbus_rx_stack2),
+ (k_thread_entry_t)canbus_np_rx, ctx, NULL, NULL,
+ K_PRIO_PREEMPT(14), 0, K_NO_WAIT);
+ }
+
+ return 0;
+}
+
+DEVICE_DT_INST_DEFINE(1, &canbus_np2_init, NULL,
+ (void *)&canbus_context_data2, NULL,
+ POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
+ &can_api_funcs);
+#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED */
+
+#if defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED) || \
+ defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED)
+
+#if defined(CONFIG_NET_SOCKETS_CAN)
+
+#include "socket_can_generic.h"
+
+static int socket_can_np_setsockopt(const struct device *dev, void *obj, int level,
+ int optname, const void *optval,
+ socklen_t optlen)
+{
+ struct socket_can_context *socket_context = dev->data;
+ struct can_filter filter;
+
+ if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Our userspace can send either zcan_filter or can_filter struct.
+ * They are different sizes so we need to convert them if needed.
+ */
+ if (optlen != sizeof(struct can_filter) &&
+ optlen != sizeof(struct zcan_filter)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (optlen == sizeof(struct zcan_filter)) {
+ can_copy_zfilter_to_filter((struct zcan_filter *)optval,
+ &filter);
+ } else {
+ memcpy(&filter, optval, sizeof(filter));
+ }
+
+ return canbus_np_setsockopt(socket_context->dev_fd, level, optname,
+ &filter, sizeof(filter));
+}
+
+static struct canbus_api socket_can_np_api = {
+ .iface_api.init = socket_can_iface_init,
+ .send = socket_can_send,
+ .close = socket_can_close,
+ .setsockopt = socket_can_np_setsockopt,
+};
+
+#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED
+
+static int socket_can_init_1(const struct device *dev)
+{
+ /* To avoid warning, use socket_can_api defined in socket_can_generic.h.
+ * For native posix, use socket_can_np_api instead.
+ */
+ (void)socket_can_api;
+
+ const struct device *can_dev = DEVICE_DT_INST_GET(0);
+ struct socket_can_context *socket_context = dev->data;
+
+ LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", dev,
+ dev->name, can_dev, can_dev->name);
+
+ socket_context->can_dev = can_dev;
+
+ return 0;
+}
+
+NET_DEVICE_INIT_INSTANCE(socket_can_native_posix_1,
+ CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_SOCKETCAN_NAME, 0,
+ socket_can_init_1, NULL,
+ &canbus_context_data1, NULL,
+ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_np_api,
+ CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU);
+#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED */
+
+#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED
+
+static int socket_can_init_2(const struct device *dev)
+{
+ /* To avoid warning, use socket_can_api defined in socket_can_generic.h.
+ * For native posix, use socket_can_np_api instead.
+ */
+ (void)socket_can_api;
+
+ const struct device *can_dev = DEVICE_DT_INST_GET(1);
+ struct socket_can_context *socket_context = dev->data;
+
+ LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", dev,
+ dev->name, can_dev, can_dev->name);
+
+ socket_context->can_dev = can_dev;
+
+ return 0;
+}
+
+NET_DEVICE_INIT_INSTANCE(socket_can_native_posix_2,
+ CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_SOCKETCAN_NAME, 1,
+ socket_can_init_2, NULL,
+ &canbus_context_data2, NULL,
+ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_np_api,
+ CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU);
+#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED */
+
+#endif /* CONFIG_NET_SOCKETS_CAN */
+
+#endif /* CAN_NATIVE_POSIX_INTERFACE_1_ENABLED || CAN_NATIVE_POSIX_INTERFACE_2_ENABLED */
diff --git a/drivers/can/can_native_posix_adapt.c b/drivers/can/can_native_posix_adapt.c
new file mode 100644
index 0000000000000..b7bb51d84b85c
--- /dev/null
+++ b/drivers/can/can_native_posix_adapt.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2019 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ *
+ * Routines setting up the host system. Those are placed in separate file
+ * because there is naming conflicts between host and zephyr network stacks.
+ */
+
+/* Host include files */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "arch/posix/posix_trace.h"
+
+#ifdef __linux
+#include
+#endif
+
+/* Zephyr include files. Be very careful here and only include minimum
+ * things needed.
+ */
+#define LOG_MODULE_NAME canbus_posix_adapt
+#define LOG_LEVEL CONFIG_CAN_LOG_LEVEL
+
+#include
+LOG_MODULE_REGISTER(LOG_MODULE_NAME);
+
+#include
+
+#include "can_native_posix_priv.h"
+
+int canbus_np_iface_open(const char *if_name)
+{
+ struct sockaddr_can addr;
+ struct ifreq ifr;
+ int fd, ret = -EINVAL;
+
+ fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+ if (fd < 0) {
+ return -errno;
+ }
+
+ (void)memset(&ifr, 0, sizeof(ifr));
+ (void)memset(&addr, 0, sizeof(addr));
+
+#ifdef __linux
+ strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+ ret = ioctl(fd, SIOCGIFINDEX, (void *)&ifr);
+ if (ret < 0) {
+ ret = -errno;
+ close(fd);
+ return ret;
+ }
+
+ /* Setup address for bind */
+ addr.can_ifindex = ifr.ifr_ifindex;
+ addr.can_family = PF_CAN;
+
+ /* bind socket to the zcan interface */
+ ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ ret = -errno;
+ close(fd);
+ return ret;
+ }
+#endif
+
+ return fd;
+}
+
+int canbus_np_iface_remove(int fd)
+{
+ return close(fd);
+}
+
+static int ssystem(const char *fmt, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+
+static int ssystem(const char *fmt, ...)
+{
+ char cmd[255];
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ vsnprintf(cmd, sizeof(cmd), fmt, ap);
+ va_end(ap);
+
+ posix_print_trace("%s\n", cmd);
+
+ ret = system(cmd);
+
+ return -WEXITSTATUS(ret);
+}
+
+int canbus_np_wait_data(int fd)
+{
+ struct timeval timeout;
+ fd_set rset;
+ int ret;
+
+ FD_ZERO(&rset);
+
+ FD_SET(fd, &rset);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ ret = select(fd + 1, &rset, NULL, NULL, &timeout);
+ if (ret < 0 && errno != EINTR) {
+ return -errno;
+ } else if (ret > 0) {
+ if (FD_ISSET(fd, &rset)) {
+ return 0;
+ }
+ }
+
+ return -EAGAIN;
+}
+
+ssize_t canbus_np_read_data(int fd, void *buf, size_t buf_len)
+{
+ return read(fd, buf, buf_len);
+}
+
+ssize_t canbus_np_write_data(int fd, void *buf, size_t buf_len)
+{
+ return write(fd, buf, buf_len);
+}
+
+int canbus_np_setsockopt(int fd, int level, int optname,
+ const void *optval, socklen_t optlen)
+{
+ return setsockopt(fd, level, optname, optval, optlen);
+}
+
+int canbus_np_getsockopt(int fd, int level, int optname,
+ void *optval, socklen_t *optlen)
+{
+ return getsockopt(fd, level, optname, optval, optlen);
+}
+
+#if defined(CONFIG_NET_PROMISCUOUS_MODE)
+int canbus_np_promisc_mode(const char *if_name, bool enable)
+{
+ return ssystem("ip link set dev %s promisc %s",
+ if_name, enable ? "on" : "off");
+}
+#endif /* CONFIG_NET_PROMISCUOUS_MODE */
+
+/* If we have enabled manual setup, then interface cannot be
+ * taken up or down by the driver as we normally do not have
+ * enough permissions.
+ */
+
+int canbus_np_if_up(const char *if_name)
+{
+ return ssystem("ip link set dev %s up", if_name);
+}
+
+int canbus_np_if_down(const char *if_name)
+{
+ return ssystem("ip link set dev %s down", if_name);
+}
diff --git a/drivers/can/can_native_posix_priv.h b/drivers/can/can_native_posix_priv.h
new file mode 100644
index 0000000000000..1a42c22fb5bc1
--- /dev/null
+++ b/drivers/can/can_native_posix_priv.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/** @file
+ * @brief Private functions for native posix canbus driver.
+ */
+
+#ifndef ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_PRIV_H_
+#define ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_PRIV_H_
+
+int canbus_np_iface_open(const char *if_name);
+int canbus_np_iface_close(int fd);
+int canbus_np_wait_data(int fd);
+ssize_t canbus_np_read_data(int fd, void *buf, size_t buf_len);
+ssize_t canbus_np_write_data(int fd, void *buf, size_t buf_len);
+int canbus_np_setsockopt(int fd, int level, int optname,
+ const void *optval, socklen_t optlen);
+int canbus_np_getsockopt(int fd, int level, int optname,
+ void *optval, socklen_t *optlen);
+
+#endif /* ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_PRIV_H_ */
diff --git a/drivers/can/socket_can_context.h b/drivers/can/socket_can_context.h
new file mode 100644
index 0000000000000..7388e3fc81fdc
--- /dev/null
+++ b/drivers/can/socket_can_context.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+/* CANBUS related functions that are generic in all the drivers. */
+
+#include
+#include
+
+#ifndef ZEPHYR_DRIVERS_CAN_SOCKET_CAN_CONTEXT_H_
+#define ZEPHYR_DRIVERS_CAN_SOCKET_CAN_CONTEXT_H_
+
+struct socket_can_context {
+ const struct device *can_dev;
+ struct net_if *iface;
+
+ /* for can on native posix */
+ const char *if_name;
+ int dev_fd;
+
+ /* for can on embedded board */
+ struct k_msgq *msgq;
+
+ /* TODO: remove the thread and push data to net directly from rx isr */
+ k_tid_t rx_tid;
+ struct k_thread rx_thread_data;
+};
+
+#endif /* ZEPHYR_DRIVERS_CAN_SOCKET_CAN_CONTEXT_H_ */
diff --git a/drivers/can/socket_can_generic.h b/drivers/can/socket_can_generic.h
index d6afbc0d4c97a..dce1b5199e999 100644
--- a/drivers/can/socket_can_generic.h
+++ b/drivers/can/socket_can_generic.h
@@ -13,6 +13,8 @@
#ifndef ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_
#define ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_
+#include "socket_can_context.h"
+
#define SOCKET_CAN_NAME_0 "SOCKET_CAN_0"
#define SOCKET_CAN_NAME_1 "SOCKET_CAN_1"
#define SOCKET_CAN_NAME_2 "SOCKET_CAN_2"
@@ -25,16 +27,6 @@
CAN_DEFINE_MSGQ(socket_can_msgq, 5);
K_KERNEL_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE);
-struct socket_can_context {
- const struct device *can_dev;
- struct net_if *iface;
- struct k_msgq *msgq;
-
- /* TODO: remove the thread and push data to net directly from rx isr */
- k_tid_t rx_tid;
- struct k_thread rx_thread_data;
-};
-
static inline void socket_can_iface_init(struct net_if *iface)
{
const struct device *dev = net_if_get_device(iface);
diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt
index 49a0f1ec7bba6..ceea9dd42283e 100644
--- a/drivers/clock_control/CMakeLists.txt
+++ b/drivers/clock_control/CMakeLists.txt
@@ -18,6 +18,7 @@ zephyr_sources_ifdef(CONFIG_CLOCK_CONTROL_RV32M1_PCC clock_control_rv32
zephyr_sources_ifdef(CONFIG_CLOCK_CONTROL_ESP32 clock_control_esp32.c)
zephyr_sources_ifdef(CONFIG_CLOCK_CONTROL_LITEX clock_control_litex.c)
zephyr_sources_ifdef(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR clock_control_rcar_cpg_mssr.c)
+zephyr_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_XEC clock_control_mchp_xec.c)
if(CONFIG_CLOCK_CONTROL_STM32_CUBE)
if(CONFIG_SOC_SERIES_STM32MP1X)
diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig
index 2308346b9de03..5a604cc54a105 100644
--- a/drivers/clock_control/Kconfig
+++ b/drivers/clock_control/Kconfig
@@ -52,4 +52,6 @@ source "drivers/clock_control/Kconfig.litex"
source "drivers/clock_control/Kconfig.rcar"
+source "drivers/clock_control/Kconfig.xec"
+
endif # CLOCK_CONTROL
diff --git a/drivers/clock_control/Kconfig.xec b/drivers/clock_control/Kconfig.xec
new file mode 100644
index 0000000000000..22db035c88a35
--- /dev/null
+++ b/drivers/clock_control/Kconfig.xec
@@ -0,0 +1,10 @@
+# Microchip XEC
+
+# Copyright (c) 2021 Microchip Technology Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+config CLOCK_CONTROL_MCHP_XEC
+ bool "MCHP XEC PCR clock control driver"
+ depends on SOC_SERIES_MEC172X
+ help
+ Enable support for Microchip XEC PCR clock driver.
diff --git a/drivers/clock_control/clock_control_mchp_xec.c b/drivers/clock_control/clock_control_mchp_xec.c
new file mode 100644
index 0000000000000..851130fb78329
--- /dev/null
+++ b/drivers/clock_control/clock_control_mchp_xec.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2021 Microchip Technology Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT microchip_xec_pcr
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+LOG_MODULE_REGISTER(clock_control_xec, LOG_LEVEL_ERR);
+
+#define CLK32K_SIL_OSC_DELAY 256
+#define CLK32K_PLL_LOCK_WAIT (16 * 1024)
+#define CLK32K_PIN_WAIT 4096
+#define CLK32K_XTAL_WAIT (16 * 1024)
+#define CLK32K_XTAL_MON_WAIT (64 * 1024)
+
+/*
+ * Counter checks:
+ * 32KHz period counter minimum for pass/fail: 16-bit
+ * 32KHz period counter maximum for pass/fail: 16-bit
+ * 32KHz duty cycle variation max for pass/fail: 16-bit
+ * 32KHz valid count minimum: 8-bit
+ *
+ * 32768 Hz period is 30.518 us
+ * HW count resolution is 48 MHz.
+ * One 32KHz clock pulse = 1464.84 48 MHz counts.
+ */
+#define CNT32K_TMIN 1435
+#define CNT32K_TMAX 1495
+#define CNT32K_DUTY_MAX 74
+#define CNT32K_VAL_MIN 4
+
+#define DEST_PLL 0
+#define DEST_PERIPH 1
+
+#define CLK32K_FLAG_CRYSTAL_SE BIT(0)
+#define CLK32K_FLAG_PIN_FB_CRYSTAL BIT(1)
+
+#define PCR_PERIPH_RESET_SPIN 8u
+
+#define HIBTIMER_10_MS 328u
+#define HIBTIMER_300_MS 9830u
+
+#define PCR_XEC_REG_BASE \
+ ((struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr))))
+
+#define HIBTIMER_0_XEC_REG_BASE \
+ ((struct htmr_regs *)(DT_REG_ADDR(DT_NODELABEL(hibtimer0))))
+
+#define GIRQ23_XEC_REG_BASE \
+ ((struct girq_regs *)(DT_REG_ADDR(DT_NODELABEL(girq23))))
+
+enum clk32k_src {
+ CLK32K_SRC_SIL_OSC = 0,
+ CLK32K_SRC_CRYSTAL,
+ CLK32K_SRC_MAX
+};
+
+enum clk32k_dest { CLK32K_DEST_PLL = 0, CLK32K_DEST_PERIPH, CLK32K_DEST_MAX };
+
+
+/* Driver config */
+struct xec_pcr_config {
+ uintptr_t pcr_base; /* pcr base address */
+ uintptr_t vbr_base; /* vbat registers base address */
+};
+
+/* Driver convenience defines */
+
+#define PCR_NODE_LBL DT_NODELABEL(pcr)
+
+#define XEC_CORE_CLK_DIV \
+ DT_PROP_OR(PCR_NODE_LBL, core_clk_div, CONFIG_SOC_MEC172X_PROC_CLK_DIV)
+
+#define DRV_CONFIG(dev) \
+ ((const struct xec_pcr_config *)(dev)->config)
+
+#define XEC_PCR_REGS_BASE(dev) \
+ (struct pcr_regs *)(DRV_CONFIG(dev)->pcr_base)
+
+#define XEC_VBATR_REGS_BASE(dev) \
+ (struct vbatr_regs *)(DRV_CONFIG(dev)->vbr_base)
+
+/*
+ * In early Zephyr initialization we don't have timer services. Also, the SoC
+ * may be running on its ring oscillator (+/- 50% accuracy). Configuring the
+ * SoC's clock subsystem requires wait/delays. We implement a simple delay
+ * by writing to a read-only hardware register in the PCR block.
+ */
+static uint32_t spin_delay(struct pcr_regs *pcr, uint32_t cnt)
+{
+ uint32_t n;
+
+ for (n = 0U; n < cnt; n++) {
+ pcr->OSC_ID = n;
+ }
+
+ return n;
+}
+
+/*
+ * Make sure PCR sleep enables are clear except for crypto
+ * which do not have internal clock gating.
+ */
+static void pcr_slp_init(struct pcr_regs *pcr)
+{
+ pcr->SYS_SLP_CTRL = 0U;
+ SCB->SCR &= ~BIT(2);
+
+ for (int i = 0; i < MCHP_MAX_PCR_SCR_REGS; i++) {
+ pcr->SLP_EN[i] = 0U;
+ }
+
+ pcr->SLP_EN[3] = MCHP_PCR3_CRYPTO_MASK;
+}
+
+static bool is_sil_osc_enabled(struct vbatr_regs *vbr)
+{
+ if (vbr->CLK32_SRC & MCHP_VBATR_CS_SO_EN) {
+ return true;
+ }
+
+ return false;
+}
+
+static void enable_sil_osc(struct vbatr_regs *vbr)
+{
+ vbr->CLK32_SRC |= MCHP_VBATR_CS_SO_EN;
+}
+
+/* caller has enabled internal silicon 32 KHz oscillator */
+static void hib_timer_delay(uint16_t hib_timer_count)
+{
+ struct htmr_regs *htmr0 = HIBTIMER_0_XEC_REG_BASE;
+ struct girq_regs *girq23 = GIRQ23_XEC_REG_BASE;
+
+ htmr0->PRLD = 0; /* disable */
+ htmr0->CTRL = 0; /* 32k time base */
+ girq23->SRC = BIT(16); /* clear hibernation timer 0 status */
+ htmr0->PRLD = hib_timer_count;
+ if (hib_timer_count == 0) {
+ return;
+ }
+
+ while ((girq23->SRC & BIT(16)) == 0) {
+ ;
+ }
+
+ girq23->SRC = BIT(16);
+ htmr0->PRLD = 0; /* disable */
+}
+
+/*
+ * Start external 32 KHz crystal.
+ * Assumes peripheral clocks source is Silicon OSC.
+ * If current configuration matches desired crystal configuration do nothing.
+ * NOTE: Crystal requires ~300 ms to stabilize.
+ */
+static int enable_32k_crystal(const struct device *dev, uint32_t flags)
+{
+ struct vbatr_regs *const vbr = XEC_VBATR_REGS_BASE(dev);
+ uint32_t vbcs = vbr->CLK32_SRC;
+ uint32_t cfg = MCHP_VBATR_CS_XTAL_EN;
+
+ if (flags & CLK32K_FLAG_CRYSTAL_SE) {
+ cfg |= MCHP_VBATR_CS_XTAL_SE;
+ }
+
+ if ((vbcs & cfg) == cfg) {
+ return 0;
+ }
+
+ /* Configure crystal connection before enabling the crystal. */
+ vbr->CLK32_SRC &= ~(MCHP_VBATR_CS_XTAL_SE | MCHP_VBATR_CS_XTAL_DHC |
+ MCHP_VBATR_CS_XTAL_CNTR_MSK);
+ if (flags & CLK32K_FLAG_CRYSTAL_SE) {
+ vbr->CLK32_SRC |= MCHP_VBATR_CS_XTAL_SE;
+ }
+
+ /* Set crystal gain */
+ vbr->CLK32_SRC |= MCHP_VBATR_CS_XTAL_CNTR_DG;
+
+ /* enable crystal */
+ vbr->CLK32_SRC |= MCHP_VBATR_CS_XTAL_EN;
+ /* wait for crystal stabilization */
+ hib_timer_delay(HIBTIMER_300_MS);
+ /* turn off crystal high startup current */
+ vbr->CLK32_SRC |= MCHP_VBATR_CS_XTAL_DHC;
+
+ return 0;
+}
+
+/*
+ * Use PCR clock monitor hardware to test crystal output.
+ * Requires crystal to have stabilized after enable.
+ * When enabled the clock monitor hardware measures high/low, edges, and
+ * duty cycle and compares to programmed limits.
+ */
+static int check_32k_crystal(const struct device *dev)
+{
+ struct pcr_regs *const pcr = XEC_PCR_REGS_BASE(dev);
+ struct htmr_regs *htmr0 = HIBTIMER_0_XEC_REG_BASE;
+ struct girq_regs *girq23 = GIRQ23_XEC_REG_BASE;
+ uint32_t status = 0;
+ int rc = 0;
+
+ htmr0->PRLD = 0;
+ htmr0->CTRL = 0;
+ girq23->SRC = BIT(16);
+
+ pcr->CNT32K_CTRL = 0U;
+ pcr->CLK32K_MON_IEN = 0U;
+ pcr->CLK32K_MON_ISTS = MCHP_PCR_CLK32M_ISTS_MASK;
+
+ pcr->CNT32K_PER_MIN = CNT32K_TMIN;
+ pcr->CNT32K_PER_MAX = CNT32K_TMAX;
+ pcr->CNT32K_DV_MAX = CNT32K_DUTY_MAX;
+ pcr->CNT32K_VALID_MIN = CNT32K_VAL_MIN;
+
+ pcr->CNT32K_CTRL =
+ MCHP_PCR_CLK32M_CTRL_PER_EN | MCHP_PCR_CLK32M_CTRL_DC_EN |
+ MCHP_PCR_CLK32M_CTRL_VAL_EN | MCHP_PCR_CLK32M_CTRL_CLR_CNT;
+
+ rc = -ETIMEDOUT;
+ htmr0->PRLD = HIBTIMER_10_MS;
+ status = pcr->CLK32K_MON_ISTS;
+
+ while ((girq23->SRC & BIT(16)) == 0) {
+ if (status == (MCHP_PCR_CLK32M_ISTS_PULSE_RDY |
+ MCHP_PCR_CLK32M_ISTS_PASS_PER |
+ MCHP_PCR_CLK32M_ISTS_PASS_DC |
+ MCHP_PCR_CLK32M_ISTS_VALID)) {
+ rc = 0;
+ break;
+ }
+
+ if (status & (MCHP_PCR_CLK32M_ISTS_FAIL |
+ MCHP_PCR_CLK32M_ISTS_STALL)) {
+ rc = -EBUSY;
+ break;
+ }
+
+ status = pcr->CLK32K_MON_ISTS;
+ }
+
+ pcr->CNT32K_CTRL = 0u;
+ htmr0->PRLD = 0;
+ girq23->SRC = BIT(16);
+
+ return rc;
+}
+
+/*
+ * Set the clock source for either PLL or Peripheral-32K clock domain.
+ * The source must be a stable 32 KHz input: internal silicon oscillator,
+ * external crystal (parallel or single ended connection), or a 50% duty cycle
+ * waveform on the 32KHZ_PIN. The driver does not implement 32KHZ_PIN support
+ * at this time.
+ */
+static void connect_32k_source(const struct device *dev, enum clk32k_src src,
+ enum clk32k_dest dest, uint32_t flags)
+{
+ struct pcr_regs *const pcr = XEC_PCR_REGS_BASE(dev);
+ struct vbatr_regs *const vbr = XEC_VBATR_REGS_BASE(dev);
+
+ if (dest == CLK32K_DEST_PLL) {
+ switch (src) {
+ case CLK32K_SRC_SIL_OSC:
+ pcr->CLK32K_SRC_VTR = MCHP_PCR_VTR_32K_SRC_SILOSC;
+ break;
+ case CLK32K_SRC_CRYSTAL:
+ pcr->CLK32K_SRC_VTR = MCHP_PCR_VTR_32K_SRC_XTAL;
+ break;
+ default: /* do not touch HW */
+ break;
+ }
+ } else if (dest == CLK32K_DEST_PERIPH) {
+ uint32_t vbcs = vbr->CLK32_SRC & ~(MCHP_VBATR_CS_PCS_MSK);
+
+ switch (src) {
+ case CLK32K_SRC_SIL_OSC:
+ vbr->CLK32_SRC = vbcs | MCHP_VBATR_CS_PCS_VTR_VBAT_SO;
+ break;
+ case CLK32K_SRC_CRYSTAL:
+ vbr->CLK32_SRC = vbcs | MCHP_VBATR_CS_PCS_VTR_VBAT_XTAL;
+ break;
+ default: /* do not touch HW */
+ break;
+ }
+ }
+}
+
+/*
+ * This routine checks if the PLL is locked to its input source. Minimum lock
+ * time is 3.3 ms. Lock time can be larger when the source is an external
+ * crystal. Crystal cold start times may vary greatly based on many factors.
+ * Crystals do not like being power cycled.
+ */
+static int pll_wait_lock(struct pcr_regs *const pcr, uint32_t wait_cnt)
+{
+ while (!(pcr->OSC_ID & MCHP_PCR_OSC_ID_PLL_LOCK)) {
+ if (wait_cnt == 0) {
+ return -ETIMEDOUT;
+ }
+ --wait_cnt;
+ }
+
+ return 0;
+}
+
+/*
+ * MEC172x has two 32 KHz clock domains
+ * PLL domain: 32 KHz clock input for PLL to produce 96 MHz and 48 MHz clocks
+ * Peripheral domain: 32 KHz clock for subset of peripherals.
+ * Each domain 32 KHz clock input can be from one of the following sources:
+ * Internal Silicon oscillator: +/- 2%
+ * External Crystal connected as parallel or single ended
+ * External 32KHZ_PIN 50% duty cycle waveform with fall back to either
+ * Silicon OSC or crystal when 32KHZ_PIN signal goes away or VTR power rail
+ * goes off.
+ * At chip reset the PLL is held in reset and the +/- 50% ring oscillator is
+ * the main clock.
+ * If no VBAT reset occurs the VBAT 32 KHz soure register maintains its state.
+ */
+static int soc_clk32_init(const struct device *dev,
+ enum clk32k_src pll_clk_src,
+ enum clk32k_src periph_clk_src,
+ uint32_t flags)
+{
+ struct pcr_regs *const pcr = XEC_PCR_REGS_BASE(dev);
+ struct vbatr_regs *const vbr = XEC_VBATR_REGS_BASE(dev);
+ int rc = 0;
+
+ /* disable PCR 32K monitor and clear counters */
+ pcr->CNT32K_CTRL = MCHP_PCR_CLK32M_CTRL_CLR_CNT;
+ pcr->CLK32K_MON_ISTS = MCHP_PCR_CLK32M_ISTS_MASK;
+ pcr->CLK32K_MON_IEN = 0;
+
+ if (!is_sil_osc_enabled(vbr)) {
+ enable_sil_osc(vbr);
+ spin_delay(pcr, CLK32K_SIL_OSC_DELAY);
+ }
+
+ /* Default to 32KHz Silicon OSC for PLL and peripherals */
+ connect_32k_source(dev, CLK32K_SRC_SIL_OSC, CLK32K_DEST_PLL, 0);
+ connect_32k_source(dev, CLK32K_SRC_SIL_OSC, CLK32K_DEST_PERIPH, 0);
+
+ rc = pll_wait_lock(pcr, CLK32K_PLL_LOCK_WAIT);
+ if (rc) {
+ return rc;
+ }
+
+ /* We only allow Silicon OSC or Crystal as a source. */
+ if ((pll_clk_src == CLK32K_SRC_CRYSTAL) ||
+ (periph_clk_src == CLK32K_SRC_CRYSTAL)) {
+ enable_32k_crystal(dev, flags);
+ rc = check_32k_crystal(dev);
+ if (rc) {
+ /* disable crystal */
+ vbr->CLK32_SRC &= ~(MCHP_VBATR_CS_XTAL_EN);
+ return rc;
+ }
+ if (pll_clk_src == CLK32K_SRC_CRYSTAL) {
+ connect_32k_source(dev, CLK32K_SRC_CRYSTAL,
+ CLK32K_DEST_PLL, flags);
+ }
+ if (periph_clk_src == CLK32K_SRC_CRYSTAL) {
+ connect_32k_source(dev, CLK32K_SRC_CRYSTAL,
+ CLK32K_DEST_PERIPH, flags);
+ }
+ rc = pll_wait_lock(pcr, CLK32K_PLL_LOCK_WAIT);
+ }
+
+ return rc;
+}
+
+/*
+ * MEC172x Errata document DS80000913C
+ * Programming the PCR clock divider that divides the clock input to the ARM
+ * Cortex-M4 may cause a clock glitch. The recommended work-around is to
+ * issue four NOP instruction before and after the write to the PCR processor
+ * clock control register. The final four NOP instructions are followed by
+ * data and instruction barriers to flush the Cortex-M4's pipeline.
+ * NOTE: Zephyr provides inline functions for Cortex-Mx NOP but not for
+ * data and instruction barrier instructions. Caller's should only invoke this
+ * function with interrupts locked.
+ */
+static void xec_clock_control_core_clock_divider_set(uint8_t clkdiv)
+{
+ struct pcr_regs *const pcr =
+ (struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr)));
+
+ arch_nop();
+ arch_nop();
+ arch_nop();
+ arch_nop();
+ pcr->PROC_CLK_CTRL = (uint32_t)clkdiv;
+ arch_nop();
+ arch_nop();
+ arch_nop();
+ arch_nop();
+ __DSB();
+ __ISB();
+}
+
+/*
+ * PCR peripheral sleep enable allows the clocks to a specific peripheral to
+ * be gated off if the peripheral is not requesting a clock.
+ * slp_idx = zero based index into 32-bit PCR sleep enable registers.
+ * slp_pos = bit position in the register
+ * slp_en if non-zero set the bit else clear the bit
+ */
+int z_mchp_xec_pcr_periph_sleep(uint8_t slp_idx, uint8_t slp_pos,
+ uint8_t slp_en)
+{
+ struct pcr_regs *regs = PCR_XEC_REG_BASE;
+
+ if ((slp_idx >= MCHP_MAX_PCR_SCR_REGS) || (slp_pos >= 32)) {
+ return -EINVAL;
+ }
+
+ if (slp_en) {
+ regs->SLP_EN[slp_idx] |= BIT(slp_pos);
+ } else {
+ regs->SLP_EN[slp_idx] &= ~BIT(slp_pos);
+ }
+
+ return 0;
+}
+
+/* clock control driver API implementation */
+
+static int xec_cc_on(const struct device *dev,
+ clock_control_subsys_t sub_system,
+ bool turn_on)
+{
+ struct pcr_regs *const pcr = XEC_PCR_REGS_BASE(dev);
+ struct mchp_xec_pcr_clk_ctrl *cc =
+ (struct mchp_xec_pcr_clk_ctrl *)sub_system;
+ uint16_t pcr_idx = 0;
+ uint16_t bitpos = 0;
+
+ if (!cc) {
+ return -EINVAL;
+ }
+
+ switch (MCHP_XEC_CLK_SRC_GET(cc->pcr_info)) {
+ case MCHP_XEC_PCR_CLK_CORE:
+ case MCHP_XEC_PCR_CLK_BUS:
+ break;
+ case MCHP_XEC_PCR_CLK_CPU:
+ if (cc->pcr_info & MCHP_XEC_CLK_CPU_MASK) {
+ uint32_t lock = irq_lock();
+
+ xec_clock_control_core_clock_divider_set(
+ cc->pcr_info & MCHP_XEC_CLK_CPU_MASK);
+
+ irq_unlock(lock);
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case MCHP_XEC_PCR_CLK_PERIPH:
+ case MCHP_XEC_PCR_CLK_PERIPH_FAST:
+ pcr_idx = MCHP_XEC_PCR_SCR_GET_IDX(cc->pcr_info);
+ bitpos = MCHP_XEC_PCR_SCR_GET_BITPOS(cc->pcr_info);
+
+ if (pcr_idx >= MCHP_MAX_PCR_SCR_REGS) {
+ return -EINVAL;
+ }
+
+ if (turn_on) {
+ pcr->SLP_EN[pcr_idx] &= ~BIT(bitpos);
+ } else {
+ pcr->SLP_EN[pcr_idx] |= BIT(bitpos);
+ }
+ break;
+ case MCHP_XEC_PCR_CLK_PERIPH_SLOW:
+ if (turn_on) {
+ pcr->SLOW_CLK_CTRL =
+ cc->pcr_info & MCHP_XEC_CLK_SLOW_MASK;
+ } else {
+ pcr->SLOW_CLK_CTRL = 0;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Turn on requested clock source.
+ * Core, CPU, and Bus clocks are always on except in deep sleep state.
+ * Peripheral clocks can be gated off if the peripheral's PCR sleep enable
+ * is set and the peripheral indicates it does not need a clock by clearing
+ * its PCR CLOCK_REQ read-only status.
+ * Peripheral slow clock my be turned on by writing a non-zero divider value
+ * to its PCR control register.
+ */
+static int xec_clock_control_on(const struct device *dev,
+ clock_control_subsys_t sub_system)
+{
+ return xec_cc_on(dev, sub_system, true);
+}
+
+/*
+ * Turn off clock source.
+ * Core, CPU, and Bus clocks are always on except in deep sleep when PLL is
+ * turned off. Exception is 32 KHz clock.
+ * Peripheral clocks are gated off when the peripheral's sleep enable is set
+ * and the peripheral indicates is no longer needs a clock by de-asserting
+ * its read-only PCR CLOCK_REQ bit.
+ * Peripheral slow clock can be turned off by writing 0 to its control register.
+ */
+static inline int xec_clock_control_off(const struct device *dev,
+ clock_control_subsys_t sub_system)
+{
+ return xec_cc_on(dev, sub_system, false);
+}
+
+/*
+ * MEC172x clock subsystem:
+ * Two main clock domains: PLL and Peripheral-32K. Each domain's 32 KHz source
+ * can be selected from one of three inputs:
+ * internal silicon OSC +/- 2% accuracy
+ * external crystal connected parallel or single ended
+ * external 32 KHz 50% duty cycle waveform on 32KHZ_IN pin.
+ * PLL domain supplies 96 MHz, 48 MHz, and other high speed clocks to all
+ * peripherals except those in the Peripheral-32K clock domain. The slow clock
+ * is derived from the 48 MHz produced by the PLL.
+ * ARM Cortex-M4 core input: 96MHz
+ * AHB clock input: 48 MHz
+ * Fast AHB peripherals: 96 MHz internal and 48 MHz AHB interface.
+ * Slow clock peripherals: PWM, TACH, PROCHOT
+ * Peripheral-32K domain peripherals:
+ * WDT, RTC, RTOS timer, hibernation timers, week timer
+ *
+ * Peripherals using both PLL and 32K clock domains:
+ * BBLED, RPMFAN
+ */
+static int xec_clock_control_get_subsys_rate(const struct device *dev,
+ clock_control_subsys_t sub_system,
+ uint32_t *rate)
+{
+ struct pcr_regs *const pcr = XEC_PCR_REGS_BASE(dev);
+ uint32_t bus = (uint32_t)sub_system;
+ uint32_t temp = 0;
+
+ switch (bus) {
+ case MCHP_XEC_PCR_CLK_CORE:
+ case MCHP_XEC_PCR_CLK_PERIPH_FAST:
+ *rate = MHZ(96);
+ break;
+ case MCHP_XEC_PCR_CLK_CPU:
+ /* if PCR PROC_CLK_CTRL is 0 the chip is not running */
+ *rate = MHZ(96) / pcr->PROC_CLK_CTRL;
+ break;
+ case MCHP_XEC_PCR_CLK_BUS:
+ case MCHP_XEC_PCR_CLK_PERIPH:
+ *rate = MHZ(48);
+ break;
+ case MCHP_XEC_PCR_CLK_PERIPH_SLOW:
+ temp = pcr->SLOW_CLK_CTRL;
+ if (pcr->SLOW_CLK_CTRL) {
+ *rate = MHZ(48) / temp;
+ } else {
+ *rate = 0; /* slow clock off */
+ }
+ break;
+ default:
+ *rate = 0;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_PM)
+void mchp_xec_clk_ctrl_sys_sleep_enable(bool is_deep)
+{
+ struct pcr_regs *const pcr =
+ (struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr)));
+ uint32_t sys_sleep_mode = MCHP_PCR_SYS_SLP_CTRL_SLP_ALL;
+
+ if (is_deep) {
+ sys_sleep_mode |= MCHP_PCR_SYS_SLP_CTRL_SLP_HEAVY;
+ }
+
+ SCB->SCR |= BIT(2);
+ pcr->SYS_SLP_CTRL = sys_sleep_mode;
+}
+
+void mchp_xec_clk_ctrl_sys_sleep_disable(void)
+{
+ struct pcr_regs *const pcr =
+ (struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr)));
+
+ pcr->SYS_SLP_CTRL = 0;
+ SCB->SCR &= ~BIT(2);
+}
+#endif
+
+/* Clock controller driver registration */
+static struct clock_control_driver_api xec_clock_control_api = {
+ .on = xec_clock_control_on,
+ .off = xec_clock_control_off,
+ .get_rate = xec_clock_control_get_subsys_rate,
+};
+
+static int xec_clock_control_init(const struct device *dev)
+{
+ int rc = 0;
+ uint32_t clk32_flags = 0;
+ struct pcr_regs *const pcr = XEC_PCR_REGS_BASE(dev);
+ enum clk32k_src clk_src_pll =
+ DT_PROP_OR(PCR_NODE_LBL, pll_32k_src, CLK32K_SRC_SIL_OSC);
+ enum clk32k_src clk_src_periph =
+ DT_PROP_OR(PCR_NODE_LBL, periph_32k_src, CLK32K_SRC_SIL_OSC);
+
+ pcr_slp_init(pcr);
+
+ rc = soc_clk32_init(dev, clk_src_pll, clk_src_periph, clk32_flags);
+ __ASSERT(rc == 0, "XEC: PLL and 32 KHz clock initialization failed");
+
+ xec_clock_control_core_clock_divider_set(XEC_CORE_CLK_DIV);
+
+ return rc;
+}
+
+const struct xec_pcr_config xec_config = {
+ .pcr_base = DT_INST_REG_ADDR_BY_IDX(0, 0),
+ .vbr_base = DT_INST_REG_ADDR_BY_IDX(0, 1),
+};
+
+DEVICE_DT_INST_DEFINE(0,
+ &xec_clock_control_init,
+ NULL,
+ NULL, &xec_config,
+ PRE_KERNEL_1,
+ CONFIG_KERNEL_INIT_PRIORITY_OBJECTS,
+ &xec_clock_control_api);
diff --git a/drivers/clock_control/clock_stm32g4.c b/drivers/clock_control/clock_stm32g4.c
index b1cdb32246fad..cf370cf84453c 100644
--- a/drivers/clock_control/clock_stm32g4.c
+++ b/drivers/clock_control/clock_stm32g4.c
@@ -49,7 +49,7 @@ void config_enable_default_clocks(void)
/* Enable the power interface clock */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
-#ifdef STM32_LSE_CLOCK
+#if STM32_LSE_CLOCK
/* LSE belongs to the back-up domain, enable access.*/
/* Set the DBP bit in the Power control register 1 (PWR_CR1) */
diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt
index 97ab401878ace..9b57e095fdbd0 100644
--- a/drivers/gpio/CMakeLists.txt
+++ b/drivers/gpio/CMakeLists.txt
@@ -2,6 +2,7 @@
zephyr_library()
+zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_CC13XX_CC26XX gpio_cc13xx_cc26xx.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_CC32XX gpio_cc32xx.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_CMSDK_AHB gpio_cmsdk_ahb.c)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 309027fc7ed23..77712ece0ead8 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -21,6 +21,8 @@ config GPIO_SHELL
help
Enable GPIO Shell for testing.
+source "drivers/gpio/Kconfig.b91"
+
source "drivers/gpio/Kconfig.dw"
source "drivers/gpio/Kconfig.pca95xx"
diff --git a/drivers/gpio/Kconfig.b91 b/drivers/gpio/Kconfig.b91
new file mode 100644
index 0000000000000..f6c26077ca054
--- /dev/null
+++ b/drivers/gpio/Kconfig.b91
@@ -0,0 +1,10 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+# Telink B91 GPIO configuration options
+
+config GPIO_TELINK_B91
+ bool "Telink B91 GPIO driver"
+ depends on SOC_RISCV_TELINK_B91
+ help
+ Enable the B91 GPIO driver.
diff --git a/drivers/gpio/gpio_b91.c b/drivers/gpio/gpio_b91.c
new file mode 100644
index 0000000000000..6e7d11d0ac9b3
--- /dev/null
+++ b/drivers/gpio/gpio_b91.c
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "analog.h"
+
+#include
+#include
+#include "gpio_utils.h"
+
+
+/* Driver dts compatibility: telink,b91_gpio */
+#define DT_DRV_COMPAT telink_b91_gpio
+
+/* Get GPIO instance */
+#define GET_GPIO(dev) ((volatile struct gpio_b91_t *) \
+ ((const struct gpio_b91_config *)dev->config)->gpio_base)
+
+/* Get GPIO configuration */
+#define GET_CFG(dev) ((const struct gpio_b91_config *)dev->config)
+
+/* Get GPIO IRQ number defined in dts */
+#define GET_IRQ_NUM(dev) (((const struct gpio_b91_config *)dev->config)->irq_num)
+
+/* Get GPIO IRQ priority defined in dts */
+#define GET_IRQ_PRIORITY(dev) (((const struct gpio_b91_config *)dev->config)->irq_priority)
+
+/* Get GPIO port number: port A - 0, port B - 1, ..., port F - 5 */
+#define GET_PORT_NUM(gpio) ((uint8_t)(((uint32_t)gpio - DT_REG_ADDR(DT_NODELABEL(gpioa))) / \
+ DT_REG_SIZE(DT_NODELABEL(gpioa))))
+
+/* Check that gpio is port C */
+#define IS_PORT_C(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpioc)))
+
+/* Check that gpio is port D */
+#define IS_PORT_D(gpio) ((uint32_t)gpio == DT_REG_ADDR(DT_NODELABEL(gpiod)))
+
+/* Check that 'inst' has only 1 interrupt selected in dts */
+#define IS_INST_IRQ_EN(inst) (DT_NUM_IRQS(DT_DRV_INST(inst)) == 1)
+
+/* Max pin number per port (pin 0..7) */
+#define PIN_NUM_MAX ((uint8_t)7u)
+
+/* IRQ Enable registers */
+#define reg_irq_risc0_en(i) REG_ADDR8(0x140338 + i)
+#define reg_irq_risc1_en(i) REG_ADDR8(0x140340 + i)
+
+/* Pull-up/down resistors */
+#define GPIO_PIN_UP_DOWN_FLOAT ((uint8_t)0u)
+#define GPIO_PIN_PULLDOWN_100K ((uint8_t)2u)
+#define GPIO_PIN_PULLUP_10K ((uint8_t)3u)
+
+/* GPIO interrupt types */
+#define INTR_RISING_EDGE ((uint8_t)0u)
+#define INTR_FALLING_EDGE ((uint8_t)1u)
+#define INTR_HIGH_LEVEL ((uint8_t)2u)
+#define INTR_LOW_LEVEL ((uint8_t)3u)
+
+/* Supported IRQ numbers */
+#define IRQ_GPIO ((uint8_t)25u)
+#define IRQ_GPIO2_RISC0 ((uint8_t)26u)
+#define IRQ_GPIO2_RISC1 ((uint8_t)27u)
+
+
+/* B91 GPIO registers structure */
+struct gpio_b91_t {
+ uint8_t input; /* Input: read GPI input */
+ uint8_t ie; /* IE: input enable, high active. 1: enable, 0: disable */
+ uint8_t oen; /* OEN: output enable, low active. 0: enable, 1: disable */
+ uint8_t output; /* Output: configure GPIO output */
+ uint8_t polarity; /* Polarity: interrupt polarity: rising, falling */
+ uint8_t ds; /* DS: drive strength. 1: maximum (default), 0: minimal */
+ uint8_t actas_gpio; /* Act as GPIO: enable (1) or disable (0) GPIO function */
+ uint8_t irq_en; /* Act as GPIO: enable (1) or disable (0) GPIO function */
+};
+
+/* GPIO driver configuration structure */
+struct gpio_b91_config {
+ struct gpio_driver_config common;
+ uint32_t gpio_base;
+ uint8_t irq_num;
+ uint8_t irq_priority;
+ void (*pirq_connect)(void);
+};
+
+/* GPIO driver data structure */
+struct gpio_b91_data {
+ struct gpio_driver_data common; /* driver data */
+ sys_slist_t callbacks; /* list of callbacks */
+};
+
+
+/* Set IRQ Enable bit based on IRQ number */
+static inline void gpiob_b91_irq_en_set(const struct device *dev, gpio_pin_t pin)
+{
+ uint8_t irq = GET_IRQ_NUM(dev);
+
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ if (irq == IRQ_GPIO) {
+ BM_SET(gpio->irq_en, BIT(pin));
+ } else if (irq == IRQ_GPIO2_RISC0) {
+ BM_SET(reg_irq_risc0_en(GET_PORT_NUM(gpio)), BIT(pin));
+ } else if (irq == IRQ_GPIO2_RISC1) {
+ BM_SET(reg_irq_risc1_en(GET_PORT_NUM(gpio)), BIT(pin));
+ } else {
+ __ASSERT(false, "Not supported GPIO IRQ number.");
+ }
+}
+
+/* Clear IRQ Enable bit based on IRQ number */
+static inline void gpiob_b91_irq_en_clr(const struct device *dev, gpio_pin_t pin)
+{
+ uint8_t irq = GET_IRQ_NUM(dev);
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ if (irq == IRQ_GPIO) {
+ BM_CLR(gpio->irq_en, BIT(pin));
+ } else if (irq == IRQ_GPIO2_RISC0) {
+ BM_CLR(reg_irq_risc0_en(GET_PORT_NUM(gpio)), BIT(pin));
+ } else if (irq == IRQ_GPIO2_RISC1) {
+ BM_CLR(reg_irq_risc1_en(GET_PORT_NUM(gpio)), BIT(pin));
+ }
+}
+
+/* Get IRQ Enable register value */
+static inline uint8_t gpio_b91_irq_en_get(const struct device *dev)
+{
+ uint8_t status = 0;
+ uint8_t irq = GET_IRQ_NUM(dev);
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ if (irq == IRQ_GPIO) {
+ status = gpio->irq_en;
+ } else if (irq == IRQ_GPIO2_RISC0) {
+ status = reg_irq_risc0_en(GET_PORT_NUM(gpio));
+ } else if (irq == IRQ_GPIO2_RISC1) {
+ status = reg_irq_risc1_en(GET_PORT_NUM(gpio));
+ }
+
+ return status;
+}
+
+/* Clear IRQ Status bit */
+static inline void gpio_b91_irq_status_clr(uint8_t irq)
+{
+ gpio_irq_status_e status = 0;
+
+ if (irq == IRQ_GPIO) {
+ status = FLD_GPIO_IRQ_CLR;
+ } else if (irq == IRQ_GPIO2_RISC0) {
+ status = FLD_GPIO_IRQ_GPIO2RISC0_CLR;
+ } else if (irq == IRQ_GPIO2_RISC1) {
+ status = FLD_GPIO_IRQ_GPIO2RISC1_CLR;
+ }
+
+ reg_gpio_irq_clr = status;
+}
+
+/* Set pin's irq type */
+void gpio_b91_irq_set(const struct device *dev, gpio_pin_t pin,
+ uint8_t trigger_type)
+{
+ uint8_t irq_lvl = 0;
+ uint8_t irq_mask = 0;
+ uint8_t irq_num = GET_IRQ_NUM(dev);
+ uint8_t irq_prioriy = GET_IRQ_PRIORITY(dev);
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ /* Get level and mask bsed on IRQ number */
+ if (irq_num == IRQ_GPIO) {
+ irq_lvl = FLD_GPIO_IRQ_LVL_GPIO;
+ irq_mask = FLD_GPIO_IRQ_MASK_GPIO;
+ } else if (irq_num == IRQ_GPIO2_RISC0) {
+ irq_lvl = FLD_GPIO_IRQ_LVL_GPIO2RISC0;
+ irq_mask = FLD_GPIO_IRQ_MASK_GPIO2RISC0;
+ } else if (irq_num == IRQ_GPIO2_RISC1) {
+ irq_lvl = FLD_GPIO_IRQ_LVL_GPIO2RISC1;
+ irq_mask = FLD_GPIO_IRQ_MASK_GPIO2RISC1;
+ }
+
+ /* Set polarity and level */
+ switch (trigger_type) {
+ case INTR_RISING_EDGE:
+ BM_CLR(gpio->polarity, BIT(pin));
+ BM_CLR(reg_gpio_irq_risc_mask, irq_lvl);
+ break;
+
+ case INTR_FALLING_EDGE:
+ BM_SET(gpio->polarity, BIT(pin));
+ BM_CLR(reg_gpio_irq_risc_mask, irq_lvl);
+ break;
+
+ case INTR_HIGH_LEVEL:
+ BM_CLR(gpio->polarity, BIT(pin));
+ BM_SET(reg_gpio_irq_risc_mask, irq_lvl);
+ break;
+
+ case INTR_LOW_LEVEL:
+ BM_SET(gpio->polarity, BIT(pin));
+ BM_SET(reg_gpio_irq_risc_mask, irq_lvl);
+ break;
+ }
+
+ if (irq_num == IRQ_GPIO) {
+ reg_gpio_irq_ctrl |= FLD_GPIO_CORE_INTERRUPT_EN;
+ }
+ gpio_b91_irq_status_clr(irq_num);
+ BM_SET(reg_gpio_irq_risc_mask, irq_mask);
+
+ /* Enable peripheral interrupt */
+ gpiob_b91_irq_en_set(dev, pin);
+
+ /* Enable PLIC interrupt */
+ riscv_plic_irq_enable(irq_num);
+ riscv_plic_set_priority(irq_num, irq_prioriy);
+}
+
+/* Set pin's pull-up/down resistor */
+static void gpio_b91_up_down_res_set(volatile struct gpio_b91_t *gpio,
+ gpio_pin_t pin,
+ uint8_t up_down_res)
+{
+ uint8_t val;
+ uint8_t mask;
+ uint8_t analog_reg;
+
+ pin = BIT(pin);
+ val = up_down_res & 0x03;
+ analog_reg = 0x0e + (GET_PORT_NUM(gpio) << 1) + ((pin & 0xf0) ? 1 : 0);
+
+ if (pin & 0x11) {
+ val = val << 0;
+ mask = 0xfc;
+ } else if (pin & 0x22) {
+ val = val << 2;
+ mask = 0xf3;
+ } else if (pin & 0x44) {
+ val = val << 4;
+ mask = 0xcf;
+ } else if (pin & 0x88) {
+ val = val << 6;
+ mask = 0x3f;
+ } else {
+ return;
+ }
+
+ analog_write_reg8(analog_reg, (analog_read_reg8(analog_reg) & mask) | val);
+}
+
+/* Config Pin pull-up / pull-down resistors */
+static void gpio_b91_config_up_down_res(volatile struct gpio_b91_t *gpio,
+ gpio_pin_t pin,
+ gpio_flags_t flags)
+{
+ if ((flags & GPIO_PULL_UP) != 0) {
+ gpio_b91_up_down_res_set(gpio, pin, GPIO_PIN_PULLUP_10K);
+ } else if ((flags & GPIO_PULL_DOWN) != 0) {
+ gpio_b91_up_down_res_set(gpio, pin, GPIO_PIN_PULLDOWN_100K);
+ } else {
+ gpio_b91_up_down_res_set(gpio, pin, GPIO_PIN_UP_DOWN_FLOAT);
+ }
+}
+
+/* Config Pin In/Out direction */
+static void gpio_b91_config_in_out(volatile struct gpio_b91_t *gpio,
+ gpio_pin_t pin,
+ gpio_flags_t flags)
+{
+ uint8_t ie_addr = 0;
+
+ /* Port C and D Input Enable registers are located in another place: analog */
+ if (IS_PORT_C(gpio)) {
+ ie_addr = areg_gpio_pc_ie;
+ } else if (IS_PORT_D(gpio)) {
+ ie_addr = areg_gpio_pd_ie;
+ }
+
+ /* Enable/disable output */
+ WRITE_BIT(gpio->oen, pin, ~flags & GPIO_OUTPUT);
+
+ /* Enable/disable input */
+ if (ie_addr != 0) {
+ /* Port C and D are located in analog space */
+ if (flags & GPIO_INPUT) {
+ analog_write_reg8(ie_addr, analog_read_reg8(ie_addr) | BIT(pin));
+ } else {
+ analog_write_reg8(ie_addr, analog_read_reg8(ie_addr) & (~BIT(pin)));
+ }
+ } else {
+ /* Input Enable registers of all other ports are located in common GPIO space */
+ WRITE_BIT(gpio->ie, pin, flags & GPIO_INPUT);
+ }
+}
+
+/* GPIO driver initialization */
+static int gpio_b91_init(const struct device *dev)
+{
+ const struct gpio_b91_config *cfg = GET_CFG(dev);
+
+ cfg->pirq_connect();
+
+ return 0;
+}
+
+/* API implementation: pin_configure */
+static int gpio_b91_pin_configure(const struct device *dev,
+ gpio_pin_t pin,
+ gpio_flags_t flags)
+{
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ /* Check input parameters: pin number */
+ if (pin > PIN_NUM_MAX) {
+ return -ENOTSUP;
+ }
+
+ /* Check input parameters: open-source and open-drain */
+ if ((flags & GPIO_SINGLE_ENDED) != 0) {
+ return -ENOTSUP;
+ }
+
+ /* Check input parameters: simultaneous in/out mode */
+ if ((flags & GPIO_OUTPUT) && (flags & GPIO_INPUT)) {
+ return -ENOTSUP;
+ }
+
+ /* Strengths not implemented */
+ if ((flags & (GPIO_DS_ALT_LOW | GPIO_DS_ALT_HIGH)) != 0) {
+ return -ENOTSUP;
+ }
+
+ /* Set GPIO init state if defined to avoid glitches */
+ if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
+ gpio->output |= BIT(pin);
+ } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
+ gpio->output &= ~BIT(pin);
+ }
+
+ /* GPIO function enable */
+ WRITE_BIT(gpio->actas_gpio, BIT(pin), 1);
+
+ /* Set GPIO pull-up / pull-down resistors */
+ gpio_b91_config_up_down_res(gpio, pin, flags);
+
+ /* Enable/disable input/output */
+ gpio_b91_config_in_out(gpio, pin, flags);
+
+ return 0;
+}
+
+/* API implementation: port_get_raw */
+static int gpio_b91_port_get_raw(const struct device *dev,
+ gpio_port_value_t *value)
+{
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ *value = gpio->input;
+
+ return 0;
+}
+
+/* API implementation: port_set_masked_raw */
+static int gpio_b91_port_set_masked_raw(const struct device *dev,
+ gpio_port_pins_t mask,
+ gpio_port_value_t value)
+{
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ gpio->output = (gpio->output & ~mask) | (value & mask);
+
+ return 0;
+}
+
+/* API implementation: port_set_bits_raw */
+static int gpio_b91_port_set_bits_raw(const struct device *dev,
+ gpio_port_pins_t mask)
+{
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ gpio->output |= mask;
+
+ return 0;
+}
+
+/* API implementation: port_clear_bits_raw */
+static int gpio_b91_port_clear_bits_raw(const struct device *dev,
+ gpio_port_pins_t mask)
+{
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ gpio->output &= ~mask;
+
+ return 0;
+}
+
+/* API implementation: port_toggle_bits */
+static int gpio_b91_port_toggle_bits(const struct device *dev,
+ gpio_port_pins_t mask)
+{
+ volatile struct gpio_b91_t *gpio = GET_GPIO(dev);
+
+ gpio->output ^= mask;
+
+ return 0;
+}
+
+/* API implementation: interrupts handler */
+#if IS_INST_IRQ_EN(0) || IS_INST_IRQ_EN(1) || IS_INST_IRQ_EN(2) || \
+ IS_INST_IRQ_EN(3) || IS_INST_IRQ_EN(4)
+static void gpio_b91_irq_handler(const struct device *dev)
+{
+ struct gpio_b91_data *data = dev->data;
+ uint8_t irq = GET_IRQ_NUM(dev);
+ uint8_t status = gpio_b91_irq_en_get(dev);
+
+ gpio_b91_irq_status_clr(irq);
+ gpio_fire_callbacks(&data->callbacks, dev, status);
+}
+#endif
+
+/* API implementation: pin_interrupt_configure */
+static int gpio_b91_pin_interrupt_configure(const struct device *dev,
+ gpio_pin_t pin,
+ enum gpio_int_mode mode,
+ enum gpio_int_trig trig)
+{
+ int ret_status = 0;
+
+ switch (mode) {
+ case GPIO_INT_MODE_DISABLED: /* GPIO interrupt disable */
+ gpiob_b91_irq_en_clr(dev, pin);
+ break;
+
+ case GPIO_INT_MODE_LEVEL:
+ if (trig == GPIO_INT_TRIG_HIGH) { /* GPIO interrupt High level */
+ gpio_b91_irq_set(dev, pin, INTR_HIGH_LEVEL);
+ } else if (trig == GPIO_INT_TRIG_LOW) { /* GPIO interrupt Low level */
+ gpio_b91_irq_set(dev, pin, INTR_LOW_LEVEL);
+ } else {
+ ret_status = -ENOTSUP;
+ }
+ break;
+
+ case GPIO_INT_MODE_EDGE:
+ if (trig == GPIO_INT_TRIG_HIGH) { /* GPIO interrupt Rising edge */
+ gpio_b91_irq_set(dev, pin, INTR_RISING_EDGE);
+ } else if (trig == GPIO_INT_TRIG_LOW) { /* GPIO interrupt Falling edge */
+ gpio_b91_irq_set(dev, pin, INTR_FALLING_EDGE);
+ } else {
+ ret_status = -ENOTSUP;
+ }
+ break;
+
+ default:
+ ret_status = -ENOTSUP;
+ break;
+ }
+
+ return ret_status;
+}
+
+/* API implementation: manage_callback */
+static int gpio_b91_manage_callback(const struct device *dev,
+ struct gpio_callback *callback,
+ bool set)
+{
+ struct gpio_b91_data *data = dev->data;
+
+ return gpio_manage_callback(&data->callbacks, callback, set);
+}
+
+/* GPIO driver APIs structure */
+static const struct gpio_driver_api gpio_b91_driver_api = {
+ .pin_configure = gpio_b91_pin_configure,
+ .port_get_raw = gpio_b91_port_get_raw,
+ .port_set_masked_raw = gpio_b91_port_set_masked_raw,
+ .port_set_bits_raw = gpio_b91_port_set_bits_raw,
+ .port_clear_bits_raw = gpio_b91_port_clear_bits_raw,
+ .port_toggle_bits = gpio_b91_port_toggle_bits,
+ .pin_interrupt_configure = gpio_b91_pin_interrupt_configure,
+ .manage_callback = gpio_b91_manage_callback
+};
+
+/* If instance 0 is present and has interrupt enabled, connect IRQ */
+#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 0
+static void gpio_b91_irq_connect_0(void)
+{
+ #if IS_INST_IRQ_EN(0)
+ IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
+ gpio_b91_irq_handler,
+ DEVICE_DT_INST_GET(0), 0);
+ #endif
+}
+#endif
+
+/* If instance 1 is present and has interrupt enabled, connect IRQ */
+#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 1
+static void gpio_b91_irq_connect_1(void)
+{
+ #if IS_INST_IRQ_EN(1)
+ IRQ_CONNECT(DT_INST_IRQN(1), DT_INST_IRQ(1, priority),
+ gpio_b91_irq_handler,
+ DEVICE_DT_INST_GET(1), 0);
+ #endif
+}
+#endif
+
+/* If instance 2 is present and has interrupt enabled, connect IRQ */
+#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 2
+static void gpio_b91_irq_connect_2(void)
+{
+ #if IS_INST_IRQ_EN(2)
+ IRQ_CONNECT(DT_INST_IRQN(2), DT_INST_IRQ(2, priority),
+ gpio_b91_irq_handler,
+ DEVICE_DT_INST_GET(2), 0);
+ #endif
+}
+#endif
+
+/* If instance 3 is present and has interrupt enabled, connect IRQ */
+#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 3
+static void gpio_b91_irq_connect_3(void)
+{
+ #if IS_INST_IRQ_EN(3)
+ IRQ_CONNECT(DT_INST_IRQN(3), DT_INST_IRQ(3, priority),
+ gpio_b91_irq_handler,
+ DEVICE_DT_INST_GET(3), 0);
+ #endif
+}
+#endif
+
+/* If instance 4 is present and has interrupt enabled, connect IRQ */
+#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 4
+static void gpio_b91_irq_connect_4(void)
+{
+ #if IS_INST_IRQ_EN(4)
+ IRQ_CONNECT(DT_INST_IRQN(4), DT_INST_IRQ(4, priority),
+ gpio_b91_irq_handler,
+ DEVICE_DT_INST_GET(4), 0);
+ #endif
+}
+#endif
+
+/* GPIO driver registration */
+#define GPIO_B91_INIT(n) \
+ static const struct gpio_b91_config gpio_b91_config_##n = { \
+ .common = { \
+ .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n) \
+ }, \
+ .gpio_base = DT_INST_REG_ADDR(n), \
+ .irq_num = DT_INST_IRQN(n), \
+ .irq_priority = DT_INST_IRQ(n, priority), \
+ .pirq_connect = gpio_b91_irq_connect_##n \
+ }; \
+ static struct gpio_b91_data gpio_b91_data_##n; \
+ \
+ DEVICE_DT_INST_DEFINE(n, gpio_b91_init, \
+ NULL, \
+ &gpio_b91_data_##n, \
+ &gpio_b91_config_##n, \
+ POST_KERNEL, \
+ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
+ &gpio_b91_driver_api);
+
+DT_INST_FOREACH_STATUS_OKAY(GPIO_B91_INIT)
diff --git a/drivers/pinmux/CMakeLists.txt b/drivers/pinmux/CMakeLists.txt
index 55fd58d73cb0e..7961fca8f4299 100644
--- a/drivers/pinmux/CMakeLists.txt
+++ b/drivers/pinmux/CMakeLists.txt
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
# Board initialization
+zephyr_sources_ifdef(CONFIG_PINMUX_TELINK_B91 pinmux_b91.c)
zephyr_sources_ifdef(CONFIG_PINMUX_CC13XX_CC26XX pinmux_cc13xx_cc26xx.c)
zephyr_sources_ifdef(CONFIG_PINMUX_ESP32 pinmux_esp32.c)
zephyr_sources_ifdef(CONFIG_PINMUX_HSDK pinmux_hsdk.c)
diff --git a/drivers/pinmux/Kconfig b/drivers/pinmux/Kconfig
index 1572fd92b24ba..668e9fbc8f152 100644
--- a/drivers/pinmux/Kconfig
+++ b/drivers/pinmux/Kconfig
@@ -24,6 +24,8 @@ config PINMUX_INIT_PRIORITY
rule for particular boards. Don't change this value unless you
know what you are doing.
+source "drivers/pinmux/Kconfig.b91"
+
source "drivers/pinmux/Kconfig.beetle"
source "drivers/pinmux/Kconfig.cc13xx_cc26xx"
diff --git a/drivers/pinmux/Kconfig.b91 b/drivers/pinmux/Kconfig.b91
new file mode 100644
index 0000000000000..cb257986cae13
--- /dev/null
+++ b/drivers/pinmux/Kconfig.b91
@@ -0,0 +1,9 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+config PINMUX_TELINK_B91
+ bool "Telink Semiconductor B91 pinmux driver"
+ depends on SOC_RISCV_TELINK_B91
+ default y
+ help
+ Enables Telink B91 pinmux driver.
diff --git a/drivers/pinmux/pinmux_b91.c b/drivers/pinmux/pinmux_b91.c
new file mode 100644
index 0000000000000..70912b32db979
--- /dev/null
+++ b/drivers/pinmux/pinmux_b91.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT telink_b91_pinmux
+
+#include "analog.h"
+#include
+
+
+/**
+ * GPIO Function Enable Register
+ * ADDR PINS
+ * gpio_en: PORT_A[0-7]
+ * gpio_en + 1*8: PORT_B[0-7]
+ * gpio_en + 2*8: PORT_C[0-7]
+ * gpio_en + 3*8: PORT_D[0-7]
+ * gpio_en + 4*8: PORT_E[0-7]
+ * gpio_en + 5*8: PORT_F[0-7]
+ */
+#define reg_gpio_en(pin) (*(volatile uint8_t *)((uint32_t)DT_INST_REG_ADDR_BY_NAME(0, gpio_en) + \
+ ((pin >> 8) * 8)))
+
+/**
+ * Function Multiplexer Register
+ * ADDR PINS
+ * pin_mux: PORT_A[0-3]
+ * pin_mux + 1: PORT_A[4-7]
+ * pin_mux + 2: PORT_B[0-3]
+ * pin_mux + 3: PORT_B[4-7]
+ * pin_mux + 4: PORT_C[0-3]
+ * pin_mux + 5: PORT_C[4-7]
+ * pin_mux + 6: PORT_D[0-3]
+ * pin_mux + 7: PORT_D[4-7]
+ * pin_mux + 0x20: PORT_E[0-3]
+ * pin_mux + 0x21: PORT_E[4-7]
+ * pin_mux + 0x26: PORT_F[0-3]
+ * pin_mux + 0x27: PORT_F[4-7]
+ */
+#define reg_pin_mux(pin) (*(volatile uint8_t *)((uint32_t)DT_INST_REG_ADDR_BY_NAME(0, pin_mux) + \
+ (((pin >> 8) < 4) ? ((pin >> 8) * 2) : 0) + \
+ (((pin >> 8) == 4) ? 0x20 : 0) + \
+ (((pin >> 8) == 5) ? 0x26 : 0) + \
+ ((pin & 0x0f0) ? 1 : 0)))
+
+/**
+ * Pull Up resistors enable
+ * ADDR PINS
+ * pull_up_en: PORT_A[0-3]
+ * pull_up_en + 1: PORT_A[4-7]
+ * pull_up_en + 2: PORT_B[0-3]
+ * pull_up_en + 3: PORT_B[4-7]
+ * pull_up_en + 4: PORT_C[0-3]
+ * pull_up_en + 5: PORT_C[4-7]
+ * pull_up_en + 6: PORT_D[0-3]
+ * pull_up_en + 7: PORT_D[4-7]
+ * pull_up_en + 8: PORT_E[0-3]
+ * pull_up_en + 9: PORT_E[4-7]
+ * pull_up_en + 10: PORT_F[0-3]
+ * pull_up_en + 11: PORT_F[4-7]
+ */
+#define reg_pull_up_en(pin) ((uint8_t)(DT_INST_REG_ADDR_BY_NAME(0, pull_up_en) + \
+ ((pin >> 8) * 2) + \
+ ((pin & 0xf0) ? 1 : 0)))
+
+/* GPIO Pull-Up options */
+#define PINMUX_B91_PULLUP_DISABLE ((uint8_t)0u)
+#define PINMUX_B91_PULLUP_10K ((uint8_t)3u)
+
+/* Get PinMux configuration */
+#define GET_CFG(dev) ((const struct pinmux_b91_config *)dev->config)
+
+
+/* B91 PinMux config structure */
+struct pinmux_b91_config {
+ uint8_t pad_mul_sel;
+};
+
+
+/* Act as GPIO function disable */
+static inline void pinmux_b91_gpio_function_disable(uint32_t pin)
+{
+ uint8_t bit = pin & 0xff;
+
+ reg_gpio_en(pin) &= ~bit;
+}
+
+/* Get function value bits start position (offset) */
+static inline int pinmux_b91_get_func_offset(uint32_t pin, uint8_t *offset)
+{
+ switch ((pin & 0x0fu) != 0u ? pin & 0x0fu : (pin & 0xf0u) >> 4u) {
+ case BIT(0):
+ *offset = 0u;
+ break;
+ case BIT(1):
+ *offset = 2u;
+ break;
+ case BIT(2):
+ *offset = 4u;
+ break;
+ case BIT(3):
+ *offset = 6u;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Set pin's pull-up/down resistor */
+static void pinmux_b91_set_pull_up(uint32_t pin, uint8_t val)
+{
+ uint8_t mask = 0;
+ uint8_t analog_reg = reg_pull_up_en(pin);
+
+ if (pin & 0x11) {
+ val = val;
+ mask = 0xfc;
+ } else if (pin & 0x22) {
+ val = val << 2;
+ mask = 0xf3;
+ } else if (pin & 0x44) {
+ val = val << 4;
+ mask = 0xcf;
+ } else if (pin & 0x88) {
+ val = val << 6;
+ mask = 0x3f;
+ } else {
+ return;
+ }
+
+ analog_write_reg8(analog_reg, (analog_read_reg8(analog_reg) & mask) | val);
+}
+
+/* API implementation: init */
+static int pinmux_b91_init(const struct device *dev)
+{
+ const struct pinmux_b91_config *cfg = GET_CFG(dev);
+
+ reg_gpio_pad_mul_sel |= cfg->pad_mul_sel;
+
+ return 0;
+}
+
+/* API implementation: set */
+static int pinmux_b91_set(const struct device *dev, uint32_t pin, uint32_t func)
+{
+ ARG_UNUSED(dev);
+
+ uint8_t mask = 0;
+ uint8_t offset = 0;
+ int32_t status = 0;
+
+ /* calculate offset and mask for the func value */
+ status = pinmux_b91_get_func_offset(pin, &offset);
+ if (status != 0) {
+ return status;
+ }
+ mask = (uint8_t)~(BIT(offset) | BIT(offset + 1));
+
+ /* disable GPIO function (can be enabled back by GPIO init using GPIO driver) */
+ pinmux_b91_gpio_function_disable(pin);
+
+ /* set func value */
+ reg_pin_mux(pin) = (reg_pin_mux(pin) & mask) | (func << offset);
+
+ return status;
+}
+
+/* API implementation: get */
+static int pinmux_b91_get(const struct device *dev, uint32_t pin, uint32_t *func)
+{
+ ARG_UNUSED(dev);
+
+ uint8_t mask = 0u;
+ uint8_t offset = 0;
+ int32_t status = 0;
+
+ /* calculate offset and mask for the func value */
+ status = pinmux_b91_get_func_offset(pin, &offset);
+ if (status != 0) {
+ return status;
+ }
+ mask = (uint8_t)(BIT(offset) | BIT(offset + 1));
+
+ /* get func value */
+ *func = (reg_pin_mux(pin) & mask) >> offset;
+
+ return status;
+}
+
+/* API implementation: pullup */
+static int pinmux_b91_pullup(const struct device *dev, uint32_t pin, uint8_t func)
+{
+ ARG_UNUSED(dev);
+
+ switch (func) {
+ case PINMUX_PULLUP_ENABLE:
+ pinmux_b91_set_pull_up(pin, PINMUX_B91_PULLUP_10K);
+ break;
+
+ case PINMUX_PULLUP_DISABLE:
+ pinmux_b91_set_pull_up(pin, PINMUX_B91_PULLUP_DISABLE);
+ break;
+
+ default:
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/* API implementation: input */
+static int pinmux_b91_input(const struct device *dev, uint32_t pin, uint8_t func)
+{
+ ARG_UNUSED(dev);
+ ARG_UNUSED(pin);
+ ARG_UNUSED(func);
+
+ /* Implemented by GPIO driver */
+
+ return -ENOTSUP;
+}
+
+/* PinMux driver APIs structure */
+static const struct pinmux_driver_api pinmux_b91_api = {
+ .set = pinmux_b91_set,
+ .get = pinmux_b91_get,
+ .pullup = pinmux_b91_pullup,
+ .input = pinmux_b91_input,
+};
+
+static const struct pinmux_b91_config pinmux_b91_cfg = {
+ .pad_mul_sel = DT_INST_PROP(0, pad_mul_sel)
+};
+
+/* PinMux driver registration */
+DEVICE_DT_INST_DEFINE(0, pinmux_b91_init,
+ NULL, NULL, &pinmux_b91_cfg, PRE_KERNEL_1,
+ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
+ &pinmux_b91_api);
diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt
index 03cd54d84ffcd..c56b5c2fa58e4 100644
--- a/drivers/serial/CMakeLists.txt
+++ b/drivers/serial/CMakeLists.txt
@@ -2,6 +2,7 @@
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_UART_ALTERA_JTAG uart_altera_jtag_hal.c)
+zephyr_library_sources_ifdef(CONFIG_UART_TELINK_B91 uart_b91.c)
zephyr_library_sources_ifdef(CONFIG_UART_IMX uart_imx.c)
zephyr_library_sources_ifdef(CONFIG_UART_CC13XX_CC26XX uart_cc13xx_cc26xx.c)
zephyr_library_sources_ifdef(CONFIG_UART_CC32XX uart_cc32xx.c)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 637c55f02b332..999f282dbb561 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -79,6 +79,8 @@ config UART_DRV_CMD
comment "Serial Drivers"
+source "drivers/serial/Kconfig.b91"
+
source "drivers/serial/Kconfig.ns16550"
source "drivers/serial/Kconfig.mcux"
diff --git a/drivers/serial/Kconfig.b91 b/drivers/serial/Kconfig.b91
new file mode 100644
index 0000000000000..298aa2be6fcab
--- /dev/null
+++ b/drivers/serial/Kconfig.b91
@@ -0,0 +1,12 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+# Telink B91 UART configuration options
+
+config UART_TELINK_B91
+ bool "Telink B91 UART driver"
+ depends on SOC_RISCV_TELINK_B91
+ select SERIAL_HAS_DRIVER
+ select SERIAL_SUPPORT_INTERRUPT
+ help
+ This option enables the B91 serial driver.
diff --git a/drivers/serial/uart_b91.c b/drivers/serial/uart_b91.c
new file mode 100644
index 0000000000000..82b45f53b3ca1
--- /dev/null
+++ b/drivers/serial/uart_b91.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "analog.h"
+#include "clock.h"
+
+#include
+#include
+#include
+#include
+
+
+/* Driver dts compatibility: telink,b91_uart */
+#define DT_DRV_COMPAT telink_b91_uart
+
+/* Get UART instance */
+#define GET_UART(dev) ((volatile struct uart_b91_t *) \
+ ((const struct uart_b91_config *)dev->config)->uart_addr)
+
+/* Get UART configuration */
+#define GET_CFG(dev) ((const struct uart_b91_config *)dev->config)
+
+/* Get instance data */
+#define DEV_DATA(dev) ((struct uart_b91_data *const)dev->data)
+
+/* UART TX buffer count max value */
+#define UART_TX_BUF_CNT ((uint8_t)8u)
+
+/* Parity type */
+#define UART_PARITY_NONE ((uint8_t)0u)
+#define UART_PARITY_EVEN ((uint8_t)1u)
+#define UART_PARITY_ODD ((uint8_t)2u)
+
+/* Stop bits length */
+#define UART_STOP_BIT_1 ((uint8_t)0u)
+#define UART_STOP_BIT_1P5 BIT(4)
+#define UART_STOP_BIT_2 BIT(5)
+
+
+/* B91 UART registers structure */
+struct uart_b91_t {
+ uint8_t data_buf[4];
+ uint16_t clk_div;
+ uint8_t ctrl0;
+ uint8_t ctrl1;
+ uint8_t ctrl2;
+ uint8_t ctrl3;
+ uint16_t rxtimeout;
+ uint8_t bufcnt;
+ uint8_t status;
+ uint8_t txrx_status;
+ uint8_t state;
+};
+
+/* B91 UART data structure */
+struct uart_b91_data {
+ uint8_t tx_byte_index;
+ uint8_t rx_byte_index;
+ struct uart_config cfg;
+#ifdef CONFIG_UART_INTERRUPT_DRIVEN
+ uart_irq_callback_user_data_t callback;
+ void *cb_data;
+#endif
+};
+
+/* B91 UART config structure */
+struct uart_b91_config {
+ const uint32_t *pinctrl_list;
+ size_t pinctrl_list_size;
+ uint32_t uart_addr;
+ uint32_t baud_rate;
+ void (*pirq_connect)(void);
+};
+
+/* rxtimeout register enums */
+enum {
+ UART_ERR_IRQ_MASK = BIT(15),
+};
+
+/* ctrl0 register enums */
+enum {
+ UART_RX_IRQ_MASK = BIT(6),
+ UART_TX_IRQ_MASK = BIT(7),
+};
+
+/* ctrl3 register enums */
+enum {
+ FLD_UART_RX_IRQ_TRIQ_LEV_OFFSET = 0,
+ FLD_UART_TX_IRQ_TRIQ_LEV_OFFSET = 4,
+};
+
+/* bufcnt register enums */
+enum {
+ FLD_UART_RX_BUF_CNT_OFFSET = 0,
+ FLD_UART_TX_BUF_CNT_OFFSET = 4,
+};
+
+/* status register enums */
+enum {
+ UART_IRQ_STATUS = BIT(3),
+ UART_RX_ERR_STATUS = BIT(7),
+};
+
+
+/* Get tx fifo count */
+static inline uint8_t uart_b91_get_tx_bufcnt(volatile struct uart_b91_t *uart)
+{
+ return (uart->bufcnt & FLD_UART_TX_BUF_CNT) >> FLD_UART_TX_BUF_CNT_OFFSET;
+}
+
+/* Get rx fifo count */
+static inline uint8_t uart_b91_get_rx_bufcnt(volatile struct uart_b91_t *uart)
+{
+ return (uart->bufcnt & FLD_UART_RX_BUF_CNT) >> FLD_UART_RX_BUF_CNT_OFFSET;
+}
+
+/* Check for prime */
+static uint8_t uart_b91_is_prime(uint32_t n)
+{
+ uint32_t i = 5;
+
+ if (n <= 3) {
+ return 1;
+ } else if ((n % 2 == 0) || (n % 3 == 0)) {
+ return 0;
+ }
+
+ for (i = 5; i * i < n; i += 6) {
+ if ((n % i == 0) || (n % (i + 2)) == 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* Calculate the best bit width */
+static void uart_b91_cal_div_and_bwpc(uint32_t baudrate, uint32_t pclk,
+ uint16_t *divider, uint8_t *bwpc)
+{
+ uint8_t i = 0, j = 0;
+ uint32_t primeInt = 0;
+ uint8_t primeDec = 0;
+ uint32_t D_intdec[13], D_int[13];
+ uint8_t D_dec[13];
+
+ primeInt = pclk / baudrate;
+ primeDec = 10 * pclk / baudrate - 10 * primeInt;
+
+ if (uart_b91_is_prime(primeInt)) {
+ primeInt += 1;
+ } else if (primeDec > 5) {
+ primeInt += 1;
+ if (uart_b91_is_prime(primeInt)) {
+ primeInt -= 1;
+ }
+ }
+
+ for (i = 3; i <= 15; i++) {
+ D_intdec[i - 3] = (10 * primeInt) / (i + 1);
+ D_dec[i - 3] = D_intdec[i - 3] - 10 * (D_intdec[i - 3] / 10);
+ D_int[i - 3] = D_intdec[i - 3] / 10;
+ }
+
+ /* find the max and min one decimation point */
+ uint8_t position_min = 0, position_max = 0;
+ uint32_t min = 0xffffffff, max = 0x00;
+
+ for (j = 0; j < 13; j++) {
+ if ((D_dec[j] <= min) && (D_int[j] != 0x01)) {
+ min = D_dec[j];
+ position_min = j;
+ }
+ if (D_dec[j] >= max) {
+ max = D_dec[j];
+ position_max = j;
+ }
+ }
+
+ if ((D_dec[position_min] < 5) && (D_dec[position_max] >= 5)) {
+ if (D_dec[position_min] < (10 - D_dec[position_max])) {
+ *bwpc = position_min + 3;
+ *divider = D_int[position_min] - 1;
+ } else {
+ *bwpc = position_max + 3;
+ *divider = D_int[position_max];
+ }
+ } else if ((D_dec[position_min] < 5) && (D_dec[position_max] < 5)) {
+ *bwpc = position_min + 3;
+ *divider = D_int[position_min] - 1;
+ } else {
+ *bwpc = position_max + 3;
+ *divider = D_int[position_max];
+ }
+}
+
+/* Initializes the UART instance */
+static void uart_b91_init(volatile struct uart_b91_t *uart, uint16_t divider,
+ uint8_t bwpc, uint8_t parity, uint8_t stop_bit)
+{
+ /* config clock */
+ divider = divider | FLD_UART_CLK_DIV_EN;
+ uart->ctrl0 = bwpc;
+ uart->clk_div = divider;
+
+ /* config parity */
+ if (parity) {
+ /* enable parity function */
+ uart->ctrl1 |= FLD_UART_PARITY_ENABLE;
+
+ if (parity == UART_PARITY_EVEN) {
+ /* enable even parity */
+ uart->ctrl1 &= (~FLD_UART_PARITY_POLARITY);
+ } else if (parity == UART_PARITY_ODD) {
+ /* enable odd parity */
+ uart->ctrl1 |= FLD_UART_PARITY_POLARITY;
+ }
+ } else {
+ uart->ctrl1 &= (~FLD_UART_PARITY_ENABLE); /* disable parity function */
+ }
+
+ /* stop bit config */
+ uart->ctrl1 &= (~FLD_UART_STOP_SEL);
+ uart->ctrl1 |= stop_bit;
+}
+
+/* API implementation: irq handler */
+static void uart_b91_irq_handler(const struct device *dev)
+{
+#ifndef CONFIG_UART_INTERRUPT_DRIVEN
+ ARG_UNUSED(dev);
+#else
+ struct uart_b91_data *data = DEV_DATA(dev);
+
+ if (data->callback != NULL) {
+ data->callback(dev, data->cb_data);
+ }
+#endif
+}
+
+/* API implementation: configure */
+static int uart_b91_configure(const struct device *dev,
+ const struct uart_config *cfg)
+{
+ uint16_t divider;
+ uint8_t bwpc;
+ uint8_t parity;
+ uint8_t stop_bits;
+
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ /* check parity */
+ if (cfg->parity == UART_CFG_PARITY_NONE) {
+ parity = UART_PARITY_NONE;
+ } else if (cfg->parity == UART_CFG_PARITY_ODD) {
+ parity = UART_PARITY_ODD;
+ } else if (cfg->parity == UART_CFG_PARITY_EVEN) {
+ parity = UART_PARITY_EVEN;
+ } else {
+ return -ENOTSUP;
+ }
+
+ /* check stop bits */
+ if (cfg->stop_bits == UART_CFG_STOP_BITS_1) {
+ stop_bits = UART_STOP_BIT_1;
+ } else if (cfg->stop_bits == UART_CFG_STOP_BITS_1_5) {
+ stop_bits = UART_STOP_BIT_1P5;
+ } else if (cfg->stop_bits == UART_CFG_STOP_BITS_2) {
+ stop_bits = UART_STOP_BIT_2;
+ } else {
+ return -ENOTSUP;
+ }
+
+ /* check flow control */
+ if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) {
+ return -ENOTSUP;
+ }
+
+ /* UART configure */
+ uart_b91_cal_div_and_bwpc(cfg->baudrate, sys_clk.pclk * 1000 * 1000, ÷r, &bwpc);
+ uart_b91_init(uart, divider, bwpc, parity, stop_bits);
+
+ /* save configuration */
+ DEV_DATA(dev)->cfg = *cfg;
+
+ return 0;
+}
+
+/* API implementation: config_get */
+static int uart_b91_config_get(const struct device *dev,
+ struct uart_config *cfg)
+{
+ *cfg = DEV_DATA(dev)->cfg;
+
+ return 0;
+}
+
+/* API implementation: driver initialization */
+static int uart_b91_driver_init(const struct device *dev)
+{
+ uint16_t divider = 0u;
+ uint8_t bwpc = 0u;
+ const struct device *pinmux;
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+ const struct uart_b91_config *cfg = GET_CFG(dev);
+
+ pinmux = DEVICE_DT_GET(DT_NODELABEL(pinmux));
+ if (!device_is_ready(pinmux)) {
+ return -ENODEV;
+ }
+
+ for (int i = 0; i < cfg->pinctrl_list_size; i++) {
+ pinmux_pin_set(pinmux, B91_PINMUX_GET_PIN(cfg->pinctrl_list[i]),
+ B91_PINMUX_GET_FUNC(cfg->pinctrl_list[i]));
+ }
+
+ uart_b91_cal_div_and_bwpc(cfg->baud_rate, sys_clk.pclk * 1000 * 1000, ÷r, &bwpc);
+ uart_b91_init(uart, divider, bwpc, UART_PARITY_NONE, UART_STOP_BIT_1);
+
+#ifdef CONFIG_UART_INTERRUPT_DRIVEN
+ cfg->pirq_connect();
+#endif
+
+ return 0;
+}
+
+/* API implementation: poll_out */
+static void uart_b91_poll_out(const struct device *dev, uint8_t c)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+ struct uart_b91_data *data = DEV_DATA(dev);
+
+ while (uart_b91_get_tx_bufcnt(uart) >= UART_TX_BUF_CNT) {
+ };
+
+ uart->data_buf[data->tx_byte_index] = c;
+ data->tx_byte_index = (data->tx_byte_index + 1) % ARRAY_SIZE(uart->data_buf);
+}
+
+/* API implementation: poll_in */
+static int uart_b91_poll_in(const struct device *dev, unsigned char *c)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+ struct uart_b91_data *data = DEV_DATA(dev);
+
+ if (uart_b91_get_rx_bufcnt(uart) == 0) {
+ return -1;
+ }
+
+ *c = uart->data_buf[data->rx_byte_index];
+ data->rx_byte_index = (data->rx_byte_index + 1) % ARRAY_SIZE(uart->data_buf);
+
+ return 0;
+}
+
+/* API implementation: err_check */
+static int uart_b91_err_check(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ return ((uart->status & UART_RX_ERR_STATUS) != 0) ? 1 : 0;
+}
+
+#ifdef CONFIG_UART_INTERRUPT_DRIVEN
+
+/* API implementation: fifo_fill */
+static int uart_b91_fifo_fill(const struct device *dev,
+ const uint8_t *tx_data,
+ int size)
+{
+ int i = 0;
+
+ for (i = 0; i < size; i++) {
+ uart_b91_poll_out(dev, tx_data[i]);
+ }
+
+ return i;
+}
+
+/* API implementation: fifo_read */
+static int uart_b91_fifo_read(const struct device *dev,
+ uint8_t *rx_data,
+ const int size)
+{
+ int rx_count;
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ for (rx_count = 0; rx_count < size; rx_count++) {
+ if (uart_b91_get_rx_bufcnt(uart) == 0) {
+ break;
+ }
+
+ uart_b91_poll_in(dev, &rx_data[rx_count]);
+ }
+
+ return rx_count;
+}
+
+/* API implementation: irq_tx_enable */
+static void uart_b91_irq_tx_enable(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ uart->ctrl3 = (uart->ctrl3 & (~FLD_UART_TX_IRQ_TRIQ_LEV)) |
+ BIT(FLD_UART_TX_IRQ_TRIQ_LEV_OFFSET);
+ uart->ctrl0 |= UART_TX_IRQ_MASK;
+}
+
+/* API implementation: irq_tx_disable */
+static void uart_b91_irq_tx_disable(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ uart->ctrl0 &= ~UART_TX_IRQ_MASK;
+}
+
+/* API implementation: irq_tx_ready */
+static int uart_b91_irq_tx_ready(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ return (uart_b91_get_tx_bufcnt(uart) < UART_TX_BUF_CNT) ? 1 : 0;
+}
+
+/* API implementation: irq_tx_complete */
+static int uart_b91_irq_tx_complete(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ return (uart_b91_get_tx_bufcnt(uart) == 0) ? 1 : 0;
+}
+
+/* API implementation: irq_rx_enable */
+static void uart_b91_irq_rx_enable(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ uart->ctrl3 = (uart->ctrl3 & (~FLD_UART_RX_IRQ_TRIQ_LEV)) |
+ BIT(FLD_UART_RX_IRQ_TRIQ_LEV_OFFSET);
+ uart->ctrl0 |= UART_RX_IRQ_MASK;
+}
+
+/* API implementation: irq_rx_disable */
+static void uart_b91_irq_rx_disable(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ uart->ctrl0 &= ~UART_RX_IRQ_MASK;
+}
+
+/* API implementation: irq_rx_ready */
+static int uart_b91_irq_rx_ready(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ return (uart_b91_get_rx_bufcnt(uart) > 0) ? 1 : 0;
+}
+
+/* API implementation: irq_err_enable */
+static void uart_b91_irq_err_enable(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ uart->rxtimeout |= UART_ERR_IRQ_MASK;
+}
+
+/* API implementation: irq_err_disable*/
+static void uart_b91_irq_err_disable(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ uart->rxtimeout &= ~UART_ERR_IRQ_MASK;
+}
+
+/* API implementation: irq_is_pending */
+static int uart_b91_irq_is_pending(const struct device *dev)
+{
+ volatile struct uart_b91_t *uart = GET_UART(dev);
+
+ return ((uart->status & UART_IRQ_STATUS) != 0) ? 1 : 0;
+}
+
+/* API implementation: irq_update */
+static int uart_b91_irq_update(const struct device *dev)
+{
+ ARG_UNUSED(dev);
+
+ /* nothing to be done */
+ return 1;
+}
+
+/* API implementation: irq_callback_set */
+static void uart_b91_irq_callback_set(const struct device *dev,
+ uart_irq_callback_user_data_t cb,
+ void *cb_data)
+{
+ struct uart_b91_data *data = DEV_DATA(dev);
+
+ data->callback = cb;
+ data->cb_data = cb_data;
+}
+
+#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
+
+static const struct uart_driver_api uart_b91_driver_api = {
+ .poll_in = uart_b91_poll_in,
+ .poll_out = uart_b91_poll_out,
+ .err_check = uart_b91_err_check,
+ .configure = uart_b91_configure,
+ .config_get = uart_b91_config_get,
+#ifdef CONFIG_UART_INTERRUPT_DRIVEN
+ .fifo_fill = uart_b91_fifo_fill,
+ .fifo_read = uart_b91_fifo_read,
+ .irq_tx_enable = uart_b91_irq_tx_enable,
+ .irq_tx_disable = uart_b91_irq_tx_disable,
+ .irq_tx_ready = uart_b91_irq_tx_ready,
+ .irq_tx_complete = uart_b91_irq_tx_complete,
+ .irq_rx_enable = uart_b91_irq_rx_enable,
+ .irq_rx_disable = uart_b91_irq_rx_disable,
+ .irq_rx_ready = uart_b91_irq_rx_ready,
+ .irq_err_enable = uart_b91_irq_err_enable,
+ .irq_err_disable = uart_b91_irq_err_disable,
+ .irq_is_pending = uart_b91_irq_is_pending,
+ .irq_update = uart_b91_irq_update,
+ .irq_callback_set = uart_b91_irq_callback_set,
+#endif
+};
+
+
+#define UART_B91_INIT(n) \
+ \
+ static void uart_b91_irq_connect_##n(void); \
+ \
+ static const uint32_t uart_pins_##n[] = \
+ B91_PINMUX_DT_INST_GET_ARRAY(n, 0); \
+ \
+ static const struct uart_b91_config uart_b91_cfg_##n = \
+ { \
+ .uart_addr = DT_INST_REG_ADDR(n), \
+ .baud_rate = DT_INST_PROP(n, current_speed), \
+ .pinctrl_list_size = ARRAY_SIZE(uart_pins_##n), \
+ .pinctrl_list = uart_pins_##n, \
+ .pirq_connect = uart_b91_irq_connect_##n \
+ }; \
+ \
+ static struct uart_b91_data uart_b91_data_##n; \
+ \
+ DEVICE_DT_INST_DEFINE(n, uart_b91_driver_init, \
+ NULL, \
+ &uart_b91_data_##n, \
+ &uart_b91_cfg_##n, \
+ PRE_KERNEL_1, \
+ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
+ (void *)&uart_b91_driver_api); \
+ \
+ static void uart_b91_irq_connect_##n(void) \
+ { \
+ IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \
+ uart_b91_irq_handler, \
+ DEVICE_DT_INST_GET(n), 0); \
+ \
+ riscv_plic_irq_enable(DT_INST_IRQN(n)); \
+ riscv_plic_set_priority(DT_INST_IRQN(n), DT_INST_IRQ(n, priority)); \
+ }
+
+DT_INST_FOREACH_STATUS_OKAY(UART_B91_INIT)
diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi
index 86cf9af079688..c43c8ecdf6088 100644
--- a/dts/arm/microchip/mec172xnsz.dtsi
+++ b/dts/arm/microchip/mec172xnsz.dtsi
@@ -8,6 +8,7 @@
#include
#include
+#include
/ {
cpus {
@@ -31,6 +32,37 @@
};
soc {
+ ecs: ecs@4000fc00 {
+ reg = <0x4000fc00 0x200>;
+ label = "ECS";
+ };
+ pcr: pcr@40080100 {
+ compatible = "microchip,xec-pcr";
+ reg = <0x40080100 0x100 0x4000a400 0x100>;
+ reg-names = "pcrr", "vbatr";
+ interrupts = <174 0>;
+ label = "PCR";
+ core-clock-div = <1>;
+ pll-32k-src = ;
+ periph-32k-src = ;
+ #clock-cells = <2>;
+ };
+ girq23: girq23@4000e12c {
+ reg = <0x4000e12c 0x14>;
+ label = "GIRQ_23";
+ };
+ hibtimer0: timer@40009800 {
+ reg = <0x40009800 0x20>;
+ interrupts = <112 0>;
+ girqs = <23 16>;
+ label = "HIBTIMER_0";
+ };
+ hibtimer1: timer@40009820 {
+ reg = <0x40009820 0x20>;
+ interrupts = <113 0>;
+ girqs = <23 17>;
+ label = "HIBTIMER_1";
+ };
uart0: uart@400f2400 {
compatible = "ns16550";
reg = <0x400f2400 0x400>;
@@ -51,6 +83,13 @@
reg-shift = <0>;
status = "disabled";
};
+ glblcfg0: glblcfg@400fff00 {
+ reg = <0x400fff00 0x40>;
+ pcrs = <2 12>;
+ label = "GLBLCFG_0";
+ #pcrs-cells = <2>;
+ status = "disabled";
+ };
};
};
diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi
index 06afd7ebb43d0..83d85d2e88563 100644
--- a/dts/arm/nxp/nxp_rt6xx_common.dtsi
+++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi
@@ -11,6 +11,10 @@
#include
/ {
+ chosen {
+ zephyr,entropy = &trng;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -51,6 +55,12 @@
&peripheral {
#address-cells = <1>;
#size-cells = <1>;
+ /*
+ * Note that the offsets here are relative to the base address
+ * defined in either nxp_rt6xx_ns.dtsi or nxp_rt6xx.dtsi. The base
+ * addresses differ between non-secure (0x40000000) and secure
+ * modes (0x50000000).
+ */
clkctl0: clkctl@1000 {
compatible = "nxp,lpc-syscon";
@@ -222,6 +232,14 @@
status = "disabled";
label = "RTC_0";
};
+
+ trng: random@138000 {
+ compatible = "nxp,kinetis-trng";
+ reg = <0x138000 0x4000>;
+ status = "okay";
+ interrupts = <31 0>;
+ label = "TRNG";
+ };
};
&nvic {
diff --git a/dts/arm/st/f4/stm32f429.dtsi b/dts/arm/st/f4/stm32f429.dtsi
index 5db367b2a24d7..8a0fa5019106d 100644
--- a/dts/arm/st/f4/stm32f429.dtsi
+++ b/dts/arm/st/f4/stm32f429.dtsi
@@ -5,3 +5,16 @@
*/
#include
+
+/ {
+ soc {
+ dac1: dac@40007400 {
+ compatible = "st,stm32-dac";
+ reg = <0x40007400 0x400>;
+ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x20000000>;
+ status = "disabled";
+ label = "DAC_1";
+ #io-channel-cells = <1>;
+ };
+ };
+};
diff --git a/dts/bindings/clock/microchip,xec-pcr.yaml b/dts/bindings/clock/microchip,xec-pcr.yaml
new file mode 100644
index 0000000000000..45412a1430d94
--- /dev/null
+++ b/dts/bindings/clock/microchip,xec-pcr.yaml
@@ -0,0 +1,52 @@
+# Copyright (c) 2021, Microchip Technology Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+description: Microchip XEC Power Clock Reset and VBAT register (PCR)
+
+compatible: "microchip,xec-pcr"
+
+include: [clock-controller.yaml, base.yaml]
+
+properties:
+ reg:
+ required: true
+
+ interrupts:
+ required: true
+
+ label:
+ required: true
+
+ core-clock-div:
+ type: int
+ required: true
+ description: Divide 96 MHz PLL clock to produce Cortex-M4 core clock
+
+ slow-clock-div:
+ type: int
+ required: false
+ description: |
+ PWM and TACH clock domain divided down from 48 MHz AHB clock. The
+ default value is 480 for 100 kHz.
+
+ pll-32k-src:
+ type: int
+ required: true
+ description: 32 KHz clock source for PLL
+
+ periph-32k-src:
+ type: int
+ required: true
+ description: 32 KHz clock source for peripherals
+
+ xtal-single-ended:
+ type: boolean
+ required: false
+ description: Use single ended crystal connection to XTAL2 pin.
+
+ "#clock-cells":
+ const: 2
+
+clock-cells:
+ - regidx
+ - bitpos
diff --git a/dts/bindings/cpu/telink,b91.yaml b/dts/bindings/cpu/telink,b91.yaml
new file mode 100644
index 0000000000000..f70640234df77
--- /dev/null
+++ b/dts/bindings/cpu/telink,b91.yaml
@@ -0,0 +1,8 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+description: Telink RISC-V CPU
+
+compatible: "telink,b91"
+
+include: cpu.yaml
diff --git a/dts/bindings/gpio/telink,b91-gpio.yaml b/dts/bindings/gpio/telink,b91-gpio.yaml
new file mode 100644
index 0000000000000..902be6ebb7333
--- /dev/null
+++ b/dts/bindings/gpio/telink,b91-gpio.yaml
@@ -0,0 +1,22 @@
+# Copyright (c) 2021, Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+description: Telink B91 GPIO node
+
+compatible: "telink,b91-gpio"
+
+include: [gpio-controller.yaml, base.yaml]
+
+properties:
+ reg:
+ required: true
+
+ label:
+ required: true
+
+ "#gpio-cells":
+ const: 2
+
+gpio-cells:
+ - pin
+ - flags
diff --git a/dts/bindings/pinctrl/telink,b91-pinmux.yaml b/dts/bindings/pinctrl/telink,b91-pinmux.yaml
new file mode 100644
index 0000000000000..68419f09f3627
--- /dev/null
+++ b/dts/bindings/pinctrl/telink,b91-pinmux.yaml
@@ -0,0 +1,29 @@
+# Copyright (c) 2021, Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+description: Telink B91 PinMux
+
+compatible: "telink,b91-pinmux"
+
+include: base.yaml
+
+properties:
+ reg:
+ required: true
+
+ label:
+ required: true
+
+ pad-mul-sel:
+ type: int
+ required: true
+ description: PinMux pad_mul_sel register values.
+
+child-binding:
+ description:
+ This binding gives a base representation of the Telink B91 pins configration.
+
+ properties:
+ pinmux:
+ required: true
+ type: int
diff --git a/dts/bindings/power/telink,b91-power.yaml b/dts/bindings/power/telink,b91-power.yaml
new file mode 100644
index 0000000000000..7132f9d027276
--- /dev/null
+++ b/dts/bindings/power/telink,b91-power.yaml
@@ -0,0 +1,27 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+description: Telink B91 power control node
+
+compatible: "telink,b91-power"
+
+include: base.yaml
+
+properties:
+ reg:
+ required: true
+
+ power-mode:
+ type: string
+ required: true
+ enum:
+ - "LDO_1P4_LDO_1P8"
+ - "DCDC_1P4_LDO_1P8"
+ - "DCDC_1P4_DCDC_1P8"
+
+ vbat-type:
+ type: string
+ required: true
+ enum:
+ - "VBAT_MAX_VALUE_LESS_THAN_3V6"
+ - "VBAT_MAX_VALUE_GREATER_THAN_3V6"
diff --git a/dts/bindings/serial/telink,b91-uart.yaml b/dts/bindings/serial/telink,b91-uart.yaml
new file mode 100644
index 0000000000000..fffb4f0e76f40
--- /dev/null
+++ b/dts/bindings/serial/telink,b91-uart.yaml
@@ -0,0 +1,19 @@
+# Copyright (c) 2021, Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+description: Telink B91 UART
+
+compatible: "telink,b91-uart"
+
+include: uart-controller.yaml
+
+properties:
+ reg:
+ required: true
+
+ interrupts:
+ required: true
+
+ pinctrl-0:
+ type: phandles
+ required: true
diff --git a/dts/riscv/telink_b91.dtsi b/dts/riscv/telink_b91.dtsi
new file mode 100644
index 0000000000000..dc37953edae3d
--- /dev/null
+++ b/dts/riscv/telink_b91.dtsi
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/dts-v1/;
+
+#include
+#include
+#include
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu0: cpu@0 {
+ reg = <0>;
+ clock-frequency = <24000000>;
+ compatible ="telink,b91", "riscv";
+ };
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "telink,telink_b91-soc";
+ ranges;
+
+ ram_ilm: memory@0 {
+ compatible = "mmio-sram";
+ };
+
+ ram_dlm: memory@80000 {
+ compatible = "mmio-sram";
+ };
+
+ flash_mspi: flash-controller@80140100 {
+ compatible = "telink,b91-flash-controller";
+ label = "flash_mspi";
+ reg = <0x80140100 0x40>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ flash: flash@20000000 {
+ compatible = "soc-nv-flash";
+ write-block-size = <1>;
+ };
+ };
+
+ power: power@80140180 {
+ compatible = "telink,b91-power";
+ reg = <0x80140180 0x40>;
+ power-mode = "LDO_1P4_LDO_1P8";
+ vbat-type = "VBAT_MAX_VALUE_GREATER_THAN_3V6";
+ status = "okay";
+ };
+
+ gpioa: gpio@80140300 {
+ compatible = "telink,b91-gpio";
+ gpio-controller;
+ interrupt-parent = <&plic0>;
+ interrupts = <25 1>, <26 1>, <27 1>;
+ reg = <0x80140300 0x08>;
+ label = "gpio_a";
+ status = "disabled";
+ #gpio-cells = <2>;
+ };
+
+ gpiob: gpio@80140308 {
+ compatible = "telink,b91-gpio";
+ gpio-controller;
+ interrupt-parent = <&plic0>;
+ interrupts = <25 1>, <26 1>, <27 1>;
+ reg = <0x80140308 0x08>;
+ label = "gpio_b";
+ status = "disabled";
+ #gpio-cells = <2>;
+ };
+
+ gpioc: gpio@80140310 {
+ compatible = "telink,b91-gpio";
+ gpio-controller;
+ interrupt-parent = <&plic0>;
+ interrupts = <25 1>, <26 1>, <27 1>;
+ reg = <0x80140310 0x08>;
+ label = "gpio_c";
+ status = "disabled";
+ #gpio-cells = <2>;
+ };
+
+ gpiod: gpio@80140318 {
+ compatible = "telink,b91-gpio";
+ gpio-controller;
+ interrupt-parent = <&plic0>;
+ interrupts = <25 1>, <26 1>, <27 1>;
+ reg = <0x80140318 0x08>;
+ label = "gpio_d";
+ status = "disabled";
+ #gpio-cells = <2>;
+ };
+
+ gpioe: gpio@80140320 {
+ compatible = "telink,b91-gpio";
+ gpio-controller;
+ interrupt-parent = <&plic0>;
+ interrupts = <25 1>, <26 1>, <27 1>;
+ reg = <0x80140320 0x08>;
+ label = "gpio_e";
+ status = "disabled";
+ #gpio-cells = <2>;
+ };
+
+ plic0: interrupt-controller@e4000000 {
+ compatible = "sifive,plic-1.0.0";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = < 0xe4000000 0x00001000
+ 0xe4002000 0x00000800
+ 0xe4200000 0x00010000 >;
+ reg-names = "prio", "irq_en", "reg";
+ riscv,max-priority = <3>;
+ riscv,ndev = <63>;
+ };
+
+ uart0: serial@80140080 {
+ compatible = "telink,b91-uart";
+ label = "uart_0";
+ reg = <0x80140080 0x40>;
+ interrupts = <19 1>;
+ interrupt-parent = <&plic0>;
+ status = "disabled";
+ };
+
+ uart1: serial@801400C0 {
+ compatible = "telink,b91-uart";
+ label = "uart_1";
+ reg = <0x801400C0 0x40>;
+ interrupts = <18 1>;
+ interrupt-parent = <&plic0>;
+ status = "disabled";
+ };
+
+ pinmux: pinmux@80140330 {
+ compatible = "telink,b91-pinmux";
+ reg = <0x80140330 0x28
+ 0x80140306 0x28
+ 0x0000000e 0x0C>;
+ reg-names = "pin_mux",
+ "gpio_en",
+ "pull_up_en";
+ label = "pinmux";
+ status = "disabled";
+
+ /* Define UART0 pins: TX(PA3 PB2 PD2), RX(PA4 PB3 PD3) */
+
+ uart0_tx_pa3: uart0_tx_pa3 {
+ pinmux = ;
+ };
+ uart0_tx_pb2: uart0_tx_pb2 {
+ pinmux = ;
+ };
+ uart0_tx_pd2: uart0_tx_pd2 {
+ pinmux = ;
+ };
+
+ uart0_rx_pa4: uart0_rx_pa4 {
+ pinmux = ;
+ };
+ uart0_rx_pb3: uart0_rx_pb3 {
+ pinmux = ;
+ };
+ uart0_rx_pd3: uart0_rx_pd3 {
+ pinmux = ;
+ };
+
+ /* Define UART1 pins: TX(PC6 PD6 PE0), RX(PC7 PD7 PE2) */
+
+ uart1_tx_pc6: uart1_tx_pc6 {
+ pinmux = ;
+ };
+ uart1_tx_pd6: uart1_tx_pd6 {
+ pinmux = ;
+ };
+ uart1_tx_pe0: uart1_tx_pe0 {
+ pinmux = ;
+ };
+
+ uart1_rx_pc7: uart1_rx_pc7 {
+ pinmux = ;
+ };
+ uart1_rx_pd7: uart1_rx_pd7 {
+ pinmux = ;
+ };
+ uart1_rx_pe2: uart1_rx_pe2 {
+ pinmux = ;
+ };
+ };
+ };
+};
diff --git a/include/bluetooth/buf.h b/include/bluetooth/buf.h
index 2c98fc25a8fb3..f0adfef9f95c0 100644
--- a/include/bluetooth/buf.h
+++ b/include/bluetooth/buf.h
@@ -23,6 +23,10 @@
#include
#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** Possible types of buffers passed around the Bluetooth stack */
enum bt_buf_type {
/** HCI command */
@@ -155,4 +159,8 @@ static inline enum bt_buf_type bt_buf_get_type(struct net_buf *buf)
* @}
*/
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_BUF_H_ */
diff --git a/include/drivers/clock_control/mchp_xec_clock_control.h b/include/drivers/clock_control/mchp_xec_clock_control.h
new file mode 100644
index 0000000000000..c87aa7cfa229b
--- /dev/null
+++ b/include/drivers/clock_control/mchp_xec_clock_control.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021 Microchip Technology Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCHP_XEC_H_
+#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCHP_XEC_H_
+
+#include
+#include
+
+/*
+ * Set/clear Microchip XEC peripheral sleep enable.
+ * SoC layer contains the chip specific sleep index and positions
+ */
+int z_mchp_xec_pcr_periph_sleep(uint8_t slp_idx, uint8_t slp_pos,
+ uint8_t slp_en);
+
+#if defined(CONFIG_PM)
+void mchp_xec_clk_ctrl_sys_sleep_enable(bool is_deep);
+void mchp_xec_clk_ctrl_sys_sleep_disable(void);
+#endif
+
+#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_LPC11U6X_CLOCK_CONTROL_H_ */
diff --git a/include/dt-bindings/clock/mchp_xec_pcr.h b/include/dt-bindings/clock/mchp_xec_pcr.h
new file mode 100644
index 0000000000000..2d2ed370ea432
--- /dev/null
+++ b/include/dt-bindings/clock/mchp_xec_pcr.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021 Microchip Technology Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCHP_XEC_H_
+#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCHP_XEC_H_
+
+/* PLL and Peripheral 32 KHz clock source */
+#define MCHP_XEC_CLK32K_SRC_SIL_OSC 0U
+#define MCHP_XEC_CLK32K_SRC_XTAL 1U
+#define MCHP_XEC_CLK32K_SRC_PIN 2U
+
+/* Crystal connection */
+#define MCHP_XEC_XTAL_PARALLEL 0U
+#define MCHP_XEC_XTAL_SINGLE_ENDED 1U
+
+/*
+ * When the 32KHz pin goes down fall back
+ * to either internal silicon oscillator
+ * or crystal.
+ */
+#define MCHP_XEC_PIN32K_FB_SIL_OSC 0U
+#define MCHP_XEC_PIN32K_FB_XTAL 1U
+
+/* clocks supported by the driver */
+#define MCHP_XEC_PCR_CLK_CORE 0
+#define MCHP_XEC_PCR_CLK_CPU 1
+#define MCHP_XEC_PCR_CLK_BUS 2
+#define MCHP_XEC_PCR_CLK_PERIPH 3
+#define MCHP_XEC_PCR_CLK_PERIPH_FAST 4
+#define MCHP_XEC_PCR_CLK_PERIPH_SLOW 5
+
+#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCHP_XEC_H_ */
diff --git a/include/dt-bindings/pinctrl/b91-pinctrl.h b/include/dt-bindings/pinctrl/b91-pinctrl.h
new file mode 100644
index 0000000000000..8878b953acd36
--- /dev/null
+++ b/include/dt-bindings/pinctrl/b91-pinctrl.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_B91_PINCTRL_COMMON_H_
+#define ZEPHYR_B91_PINCTRL_COMMON_H_
+
+/* IDs for GPIO functions */
+
+#define B91_FUNC_A 0x000000
+#define B91_FUNC_B 0x010000
+#define B91_FUNC_C 0x020000
+
+/* IDs for GPIO Ports */
+
+#define B91_PORT_A 0x0000
+#define B91_PORT_B 0x0100
+#define B91_PORT_C 0x0200
+#define B91_PORT_D 0x0300
+#define B91_PORT_E 0x0400
+
+/* IDs for GPIO Pins */
+
+#define B91_PIN_0 0x01
+#define B91_PIN_1 0x02
+#define B91_PIN_2 0x04
+#define B91_PIN_3 0x08
+#define B91_PIN_4 0x10
+#define B91_PIN_5 0x20
+#define B91_PIN_6 0x40
+#define B91_PIN_7 0x80
+
+/* Setters and getters */
+
+#define B91_PINMUX_SET(func, port, pin) (func | port | pin)
+#define B91_PINMUX_GET_FUNC(pinmux) ((pinmux >> 16) & 0xFF)
+#define B91_PINMUX_GET_PIN(pinmux) (pinmux & 0xFFFF)
+
+#define B91_PINMUX_DT_INST_GET_ELEM(idx, x, inst) \
+ DT_PROP_BY_PHANDLE_IDX(DT_DRV_INST(inst), pinctrl_##x, idx, pinmux),
+
+#define B91_PINMUX_DT_INST_GET_ARRAY(inst, x) \
+ { COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, pinctrl_##x), \
+ (UTIL_LISTIFY(DT_INST_PROP_LEN(inst, pinctrl_##x), \
+ B91_PINMUX_DT_INST_GET_ELEM, \
+ x, \
+ inst)), \
+ ()) \
+ }
+
+#endif /* ZEPHYR_B91_PINCTRL_COMMON_H_ */
diff --git a/include/linker/common-ram.ld b/include/linker/common-ram.ld
index 9fb4292a21ba6..a324f4dbcad9e 100644
--- a/include/linker/common-ram.ld
+++ b/include/linker/common-ram.ld
@@ -5,7 +5,8 @@
#define NETWORK_RAM_SECTIONS \
Z_ITERABLE_SECTION_RAM(net_if, 4) \
Z_ITERABLE_SECTION_RAM(net_if_dev, 4) \
- Z_ITERABLE_SECTION_RAM(net_l2, 4)
+ Z_ITERABLE_SECTION_RAM(net_l2, 4) \
+ Z_ITERABLE_SECTION_RAM(eth_bridge, 4)
#endif
#endif /* NETWORKING */
diff --git a/include/net/ethernet.h b/include/net/ethernet.h
index 47cc0ae0dfc75..f12bffa1dafdf 100644
--- a/include/net/ethernet.h
+++ b/include/net/ethernet.h
@@ -34,6 +34,10 @@
#include
#endif
+#if defined(CONFIG_NET_ETHERNET_BRIDGE)
+#include
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -521,6 +525,10 @@ struct ethernet_context {
ATOMIC_DEFINE(interfaces, NET_VLAN_MAX_COUNT);
#endif
+#if defined(CONFIG_NET_ETHERNET_BRIDGE)
+ struct eth_bridge_iface_context bridge;
+#endif
+
/** Carrier ON/OFF handler worker. This is used to create
* network interface UP/DOWN event when ethernet L2 driver
* notices carrier ON/OFF situation. We must not create another
diff --git a/include/net/ethernet_bridge.h b/include/net/ethernet_bridge.h
new file mode 100644
index 0000000000000..ad546c56d0a16
--- /dev/null
+++ b/include/net/ethernet_bridge.h
@@ -0,0 +1,189 @@
+/** @file
+ * @brief Ethernet Bridge public header file
+ *
+ * Ethernet Bridges connect two or more Ethernet networks together and
+ * transparently forward packets from one network to the others as if
+ * they were part of the same network.
+ */
+
+/*
+ * Copyright (c) 2021 BayLibre SAS
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_INCLUDE_NET_ETHERNET_BRIDGE_H_
+#define ZEPHYR_INCLUDE_NET_ETHERNET_BRIDGE_H_
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Ethernet Bridging API
+ * @defgroup eth_bridge Ethernet Bridging API
+ * @ingroup networking
+ * @{
+ */
+
+/** @cond INTERNAL_HIDDEN */
+
+struct eth_bridge {
+ struct k_mutex lock;
+ sys_slist_t interfaces;
+ sys_slist_t listeners;
+};
+
+#define ETH_BRIDGE_INITIALIZER(obj) \
+ { \
+ .lock = { }, \
+ .interfaces = SYS_SLIST_STATIC_INIT(&obj.interfaces), \
+ .listeners = SYS_SLIST_STATIC_INIT(&obj.listeners), \
+ }
+
+/** @endcond */
+
+/**
+ * @brief Statically define and initialize a bridge instance.
+ *
+ * @param name Name of the bridge object
+ */
+#define ETH_BRIDGE_INIT(name) \
+ Z_STRUCT_SECTION_ITERABLE(eth_bridge, name) = \
+ ETH_BRIDGE_INITIALIZER(name)
+
+struct eth_bridge_iface_context {
+ sys_snode_t node;
+ struct eth_bridge *instance;
+ bool allow_tx;
+};
+
+struct eth_bridge_listener {
+ sys_snode_t node;
+ struct k_fifo pkt_queue;
+};
+
+/**
+ * @brief Add an Ethernet network interface to a bridge
+ *
+ * This adds a network interface to a bridge. The interface is then put
+ * into promiscuous mode, all packets received by this interface are sent
+ * to the bridge, and any other packets sent to the bridge (with some
+ * exceptions) are transmitted via this interface.
+ *
+ * For transmission from the bridge to occur via this interface, it is
+ * necessary to enable TX mode with eth_bridge_iface_tx(). TX mode is
+ * initially disabled.
+ *
+ * Once an interface is added to a bridge, all its incoming traffic is
+ * diverted to the bridge. However, packets sent out with net_if_queue_tx()
+ * via this interface are not subjected to the bridge.
+ *
+ * @param br A pointer to an initialized bridge object
+ * @param iface Interface to add
+ *
+ * @return 0 if OK, negative error code otherwise.
+ */
+int eth_bridge_iface_add(struct eth_bridge *br, struct net_if *iface);
+
+/**
+ * @brief Remove an Ethernet network interface from a bridge
+ *
+ * @param br A pointer to an initialized bridge object
+ * @param iface Interface to remove
+ *
+ * @return 0 if OK, negative error code otherwise.
+ */
+int eth_bridge_iface_remove(struct eth_bridge *br, struct net_if *iface);
+
+/**
+ * @brief Enable/disable transmission mode for a bridged interface
+ *
+ * When TX mode is off, the interface may receive packets and send them to
+ * the bridge but no packets coming from the bridge will be sent through this
+ * interface. When TX mode is on, both incoming and outgoing packets are
+ * allowed.
+ *
+ * @param iface Interface to configure
+ * @param allow true to activate TX mode, false otherwise
+ *
+ * @return 0 if OK, negative error code otherwise.
+ */
+int eth_bridge_iface_allow_tx(struct net_if *iface, bool allow);
+
+/**
+ * @brief Add (register) a listener to the bridge
+ *
+ * This lets a software listener register a pointer to a provided FIFO for
+ * receiving packets sent to the bridge. The listener is responsible for
+ * emptying the FIFO with k_fifo_get() which will return a struct net_pkt
+ * pointer, and releasing the packet with net_pkt_unref() when done with it.
+ *
+ * The listener wishing not to receive any more packets should simply
+ * unregister itself with eth_bridge_listener_remove().
+ *
+ * @param br A pointer to an initialized bridge object
+ * @param l A pointer to an initialized listener instance.
+ *
+ * @return 0 if OK, negative error code otherwise.
+ */
+int eth_bridge_listener_add(struct eth_bridge *br, struct eth_bridge_listener *l);
+
+/**
+ * @brief Remove (unregister) a listener from the bridge
+ *
+ * @param br A pointer to an initialized bridge object
+ * @param l A pointer to the listener instance to be removed.
+ *
+ * @return 0 if OK, negative error code otherwise.
+ */
+int eth_bridge_listener_remove(struct eth_bridge *br, struct eth_bridge_listener *l);
+
+/**
+ * @brief Get bridge index according to pointer
+ *
+ * @param br Pointer to bridge instance
+ *
+ * @return Bridge index
+ */
+int eth_bridge_get_index(struct eth_bridge *br);
+
+/**
+ * @brief Get bridge instance according to index
+ *
+ * @param index Bridge instance index
+ *
+ * @return Pointer to bridge instance or NULL if not found.
+ */
+struct eth_bridge *eth_bridge_get_by_index(int index);
+
+/**
+ * @typedef eth_bridge_cb_t
+ * @brief Callback used while iterating over bridge instances
+ *
+ * @param br Pointer to bridge instance
+ * @param user_data User supplied data
+ */
+typedef void (*eth_bridge_cb_t)(struct eth_bridge *br, void *user_data);
+
+/**
+ * @brief Go through all the bridge instances in order to get
+ * information about them. This is mainly useful in
+ * net-shell to print data about currently active bridges.
+ *
+ * @param cb Callback to call for each bridge instance
+ * @param user_data User supplied data
+ */
+void net_eth_bridge_foreach(eth_bridge_cb_t cb, void *user_data);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZEPHYR_INCLUDE_NET_ETHERNET_BRIDGE_H_ */
diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h
index d29ca2182569f..1c2ef1dd0a78e 100644
--- a/include/net/net_pkt.h
+++ b/include/net/net_pkt.h
@@ -181,10 +181,17 @@ struct net_pkt {
* segment.
*/
#endif
+
uint8_t captured : 1; /* Set to 1 if this packet is already being
* captured
*/
+ uint8_t l2_bridged : 1; /* set to 1 if this packet comes from a bridge
+ * and already contains its L2 header to be
+ * preserved. Useful only if
+ * defined(CONFIG_NET_ETHERNET_BRIDGE).
+ */
+
union {
/* IPv6 hop limit or IPv4 ttl for this network packet.
* The value is shared between IPv6 and IPv4.
@@ -349,6 +356,18 @@ static inline void net_pkt_set_captured(struct net_pkt *pkt, bool is_captured)
pkt->captured = is_captured;
}
+static inline bool net_pkt_is_l2_bridged(struct net_pkt *pkt)
+{
+ return IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE) ? !!(pkt->l2_bridged) : 0;
+}
+
+static inline void net_pkt_set_l2_bridged(struct net_pkt *pkt, bool is_l2_bridged)
+{
+ if (IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE)) {
+ pkt->l2_bridged = is_l2_bridged;
+ }
+}
+
static inline uint8_t net_pkt_ip_hdr_len(struct net_pkt *pkt)
{
return pkt->ip_hdr_len;
diff --git a/include/sys/cbprintf_internal.h b/include/sys/cbprintf_internal.h
index d435a69c83c85..1578b069a5821 100644
--- a/include/sys/cbprintf_internal.h
+++ b/include/sys/cbprintf_internal.h
@@ -13,7 +13,10 @@
#include
#include
#include
+
+#ifdef CONFIG_CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT
#include
+#endif
/*
* Special alignment cases
@@ -336,10 +339,9 @@ do { \
"Xtensa requires aligned package."); \
BUILD_ASSERT((_align_offset % sizeof(int)) == 0, \
"Alignment offset must be multiply of a word."); \
- if (IS_ENABLED(CONFIG_CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT)) { \
- __ASSERT(!((uintptr_t)buf & (CBPRINTF_PACKAGE_ALIGNMENT - 1)), \
- "Buffer must be aligned."); \
- } \
+ IF_ENABLED(CONFIG_CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT, \
+ (__ASSERT(!((uintptr_t)buf & (CBPRINTF_PACKAGE_ALIGNMENT - 1)), \
+ "Buffer must be aligned.");)) \
uint8_t *_pbuf = buf; \
size_t _pmax = (buf != NULL) ? _inlen : INT32_MAX; \
int _pkg_len = 0; \
diff --git a/lib/os/Kconfig.cbprintf b/lib/os/Kconfig.cbprintf
index 93b38c253f6bf..f201af13ddcbd 100644
--- a/lib/os/Kconfig.cbprintf
+++ b/lib/os/Kconfig.cbprintf
@@ -127,6 +127,8 @@ config CBPRINTF_PACKAGE_LONGDOUBLE
config CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT
bool "Validate alignment of a static package buffer"
+ # To avoid self referential macro when printk is redirected to logging
+ depends on !LOG_PRINTK
help
When enabled, CBPRINTF_STATIC_PACKAGE asserts when buffer is not
properly aligned. If macro is widely used then assert may impact
diff --git a/modules/Kconfig b/modules/Kconfig
index abae13373af4d..c8aeb4eb9d04d 100644
--- a/modules/Kconfig
+++ b/modules/Kconfig
@@ -26,6 +26,7 @@ source "modules/Kconfig.sof"
source "modules/Kconfig.st"
source "modules/Kconfig.stm32"
source "modules/Kconfig.syst"
+source "modules/Kconfig.telink"
source "modules/Kconfig.tinycbor"
source "modules/Kconfig.tinycrypt"
source "modules/Kconfig.vega"
diff --git a/modules/Kconfig.telink b/modules/Kconfig.telink
new file mode 100644
index 0000000000000..d4e5e771ba76a
--- /dev/null
+++ b/modules/Kconfig.telink
@@ -0,0 +1,7 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+config HAS_TELINK_DRIVERS
+ bool "Telink Drivers"
+ help
+ This option enables Telink Drivers APIs.
diff --git a/samples/bluetooth/central_multilink/CMakeLists.txt b/samples/bluetooth/central_multilink/CMakeLists.txt
new file mode 100644
index 0000000000000..64be1f2b118ee
--- /dev/null
+++ b/samples/bluetooth/central_multilink/CMakeLists.txt
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.13.1)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(central_multilink)
+
+target_sources(app PRIVATE
+ src/main.c
+ src/central_multilink.c
+)
+
+zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
diff --git a/samples/bluetooth/central_multilink/README.rst b/samples/bluetooth/central_multilink/README.rst
new file mode 100644
index 0000000000000..1b31d8404fa63
--- /dev/null
+++ b/samples/bluetooth/central_multilink/README.rst
@@ -0,0 +1,24 @@
+.. _bluetooth_central_multilink:
+
+Bluetooth: Central
+##################
+
+Overview
+********
+
+Application demonstrating BLE Central role functionality by scanning for other
+BLE devices and establishing connection to upto 62 peripherals with a strong
+enough signal.
+
+Requirements
+************
+
+* BlueZ running on the host, or
+* A board with BLE support
+
+Building and Running
+********************
+This sample can be found under :zephyr_file:`samples/bluetooth/central_multilink`
+in the Zephyr tree.
+
+See :ref:`bluetooth samples section ` for details.
diff --git a/samples/bluetooth/central_multilink/prj.conf b/samples/bluetooth/central_multilink/prj.conf
new file mode 100644
index 0000000000000..68f8ca16f220a
--- /dev/null
+++ b/samples/bluetooth/central_multilink/prj.conf
@@ -0,0 +1,11 @@
+CONFIG_BT=y
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_AUTO_PHY_UPDATE=n
+CONFIG_BT_PRIVACY=y
+
+CONFIG_BT_MAX_CONN=62
+
+# CONFIG_BT_GATT_CLIENT=y
+
+# CONFIG_BT_SMP=y
+# CONFIG_BT_MAX_PAIRED=62
diff --git a/samples/bluetooth/central_multilink/sample.yaml b/samples/bluetooth/central_multilink/sample.yaml
new file mode 100644
index 0000000000000..46941426f07d4
--- /dev/null
+++ b/samples/bluetooth/central_multilink/sample.yaml
@@ -0,0 +1,7 @@
+sample:
+ name: Bluetooth Central Multilink
+tests:
+ sample.bluetooth.central.multilink:
+ harness: bluetooth
+ platform_allow: qemu_cortex_m3 qemu_x86 nrf52840dk_nrf52840
+ tags: bluetooth
diff --git a/samples/bluetooth/central_multilink/src/central_multilink.c b/samples/bluetooth/central_multilink/src/central_multilink.c
new file mode 100644
index 0000000000000..c84f9f47d64e1
--- /dev/null
+++ b/samples/bluetooth/central_multilink/src/central_multilink.c
@@ -0,0 +1,264 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define SCAN_INTERVAL 0x0140 /* 200 ms */
+#define SCAN_WINDOW 0x0030 /* 30 ms */
+#define INIT_INTERVAL 0x0010 /* 10 ms */
+#define INIT_WINDOW 0x0010 /* 10 ms */
+#define CONN_INTERVAL 0x00A0 /* 200 ms */
+#define CONN_LATENCY 0
+#define CONN_TIMEOUT MIN(MAX((CONN_INTERVAL * 125 * \
+ MAX(CONFIG_BT_MAX_CONN, 6) / 1000), 10), 3200)
+
+static void start_scan(void);
+
+static struct bt_conn *conn_connecting;
+static uint8_t volatile conn_count;
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+ struct net_buf_simple *ad)
+{
+ struct bt_conn_le_create_param create_param = {
+ .options = BT_CONN_LE_OPT_NONE,
+ .interval = INIT_INTERVAL,
+ .window = INIT_WINDOW,
+ .interval_coded = 0,
+ .window_coded = 0,
+ .timeout = 0,
+ };
+ struct bt_le_conn_param conn_param = {
+ .interval_min = CONN_INTERVAL,
+ .interval_max = CONN_INTERVAL,
+ .latency = CONN_LATENCY,
+ .timeout = CONN_TIMEOUT,
+ };
+ char addr_str[BT_ADDR_LE_STR_LEN];
+ int err;
+
+ if (conn_connecting) {
+ return;
+ }
+
+ /* We're only interested in connectable events */
+ if (type != BT_GAP_ADV_TYPE_ADV_IND &&
+ type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
+ return;
+ }
+
+ bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
+ printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
+
+ /* connect only to devices in close proximity */
+ if (rssi < -35) {
+ return;
+ }
+
+ if (bt_le_scan_stop()) {
+ return;
+ }
+
+ err = bt_conn_le_create(addr, &create_param, &conn_param,
+ &conn_connecting);
+ if (err) {
+ printk("Create conn to %s failed (%d)\n", addr_str, err);
+ start_scan();
+ }
+}
+
+static void start_scan(void)
+{
+ struct bt_le_scan_param scan_param = {
+ .type = BT_HCI_LE_SCAN_PASSIVE,
+ .options = BT_LE_SCAN_OPT_NONE,
+ .interval = SCAN_INTERVAL,
+ .window = SCAN_WINDOW,
+ };
+ int err;
+
+ err = bt_le_scan_start(&scan_param, device_found);
+ if (err) {
+ printk("Scanning failed to start (err %d)\n", err);
+ return;
+ }
+
+ printk("Scanning successfully started\n");
+}
+
+#if defined(CONFIG_BT_GATT_CLIENT)
+static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
+ struct bt_gatt_exchange_params *params)
+{
+ printk("MTU exchange %u %s (%u)\n", bt_conn_index(conn),
+ err == 0U ? "successful" : "failed", bt_gatt_get_mtu(conn));
+}
+
+static struct bt_gatt_exchange_params mtu_exchange_params[CONFIG_BT_MAX_CONN];
+
+static int mtu_exchange(struct bt_conn *conn)
+{
+ uint8_t conn_index;
+ int err;
+
+ conn_index = bt_conn_index(conn);
+
+ printk("MTU (%u): %u\n", conn_index, bt_gatt_get_mtu(conn));
+
+ mtu_exchange_params[conn_index].func = mtu_exchange_cb;
+
+ err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params[conn_index]);
+ if (err) {
+ printk("MTU exchange failed (err %d)", err);
+ } else {
+ printk("Exchange pending...");
+ }
+
+ return err;
+}
+#endif /* CONFIG_BT_GATT_CLIENT */
+
+static void connected(struct bt_conn *conn, uint8_t reason)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ if (reason) {
+ printk("Failed to connect to %s (%u)\n", addr, reason);
+
+ bt_conn_unref(conn_connecting);
+ conn_connecting = NULL;
+
+ start_scan();
+ return;
+ }
+
+ conn_connecting = NULL;
+
+ conn_count++;
+ if (conn_count < CONFIG_BT_MAX_CONN) {
+ start_scan();
+ }
+
+ printk("Connected (%u): %s\n", conn_count, addr);
+
+#if defined(CONFIG_BT_SMP)
+ int err = bt_conn_set_security(conn, BT_SECURITY_L2);
+
+ if (err) {
+ printk("Failed to set security (%d).\n", err);
+ }
+#endif
+
+#if defined(CONFIG_BT_GATT_CLIENT)
+ mtu_exchange(conn);
+#endif
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
+
+ bt_conn_unref(conn);
+
+ if (conn_count == CONFIG_BT_MAX_CONN) {
+ start_scan();
+ }
+ conn_count--;
+}
+
+static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("LE conn param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
+ addr, param->interval_min, param->interval_max, param->latency,
+ param->timeout);
+
+ return true;
+}
+
+static void le_param_updated(struct bt_conn *conn, uint16_t interval,
+ uint16_t latency, uint16_t timeout)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("LE conn param updated: %s int 0x%04x lat %d to %d\n",
+ addr, interval, latency, timeout);
+}
+
+#if defined(CONFIG_BT_SMP)
+static void security_changed(struct bt_conn *conn, bt_security_t level,
+ enum bt_security_err err)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ if (!err) {
+ printk("Security changed: %s level %u\n", addr, level);
+ } else {
+ printk("Security failed: %s level %u err %d\n", addr, level,
+ err);
+ }
+}
+#endif
+
+static struct bt_conn_cb conn_callbacks = {
+ .connected = connected,
+ .disconnected = disconnected,
+ .le_param_req = le_param_req,
+ .le_param_updated = le_param_updated,
+#if defined(CONFIG_BT_SMP)
+ .security_changed = security_changed,
+#endif
+};
+
+int init_central(void)
+{
+ int err;
+
+ err = bt_enable(NULL);
+ if (err) {
+ printk("Bluetooth init failed (err %d)\n", err);
+ return err;
+ }
+
+ printk("Bluetooth initialized\n");
+
+ bt_conn_cb_register(&conn_callbacks);
+
+ start_scan();
+
+ while (conn_count < CONFIG_BT_MAX_CONN) {
+ k_sleep(K_SECONDS(1));
+ }
+
+ return 0;
+}
diff --git a/samples/bluetooth/central_multilink/src/main.c b/samples/bluetooth/central_multilink/src/main.c
new file mode 100644
index 0000000000000..0018e8a014740
--- /dev/null
+++ b/samples/bluetooth/central_multilink/src/main.c
@@ -0,0 +1,14 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+int init_central(void);
+
+void main(void)
+{
+ (void)init_central();
+}
diff --git a/samples/bluetooth/peripheral_identity/CMakeLists.txt b/samples/bluetooth/peripheral_identity/CMakeLists.txt
new file mode 100644
index 0000000000000..76efd84e42b66
--- /dev/null
+++ b/samples/bluetooth/peripheral_identity/CMakeLists.txt
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.13.1)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(peripheral_identity)
+
+target_sources(app PRIVATE
+ src/main.c
+ src/peripheral_identity.c
+)
+
+zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
diff --git a/samples/bluetooth/peripheral_identity/README.rst b/samples/bluetooth/peripheral_identity/README.rst
new file mode 100644
index 0000000000000..2619e52a89533
--- /dev/null
+++ b/samples/bluetooth/peripheral_identity/README.rst
@@ -0,0 +1,24 @@
+.. _peripheral_identity:
+
+Bluetooth: Peripheral Identity
+##############################
+
+Overview
+********
+
+This sample demonstrates use of multiple identity and the ability to be
+connected to from multiple central devices.
+
+Requirements
+************
+
+* BlueZ running on the host, or
+* A board with BLE support
+
+Building and Running
+********************
+
+This sample can be found under :zephyr_file:`samples/bluetooth/peripheral_identity`
+in the Zephyr tree.
+
+See :ref:`bluetooth samples section ` for details.
diff --git a/samples/bluetooth/peripheral_identity/prj.conf b/samples/bluetooth/peripheral_identity/prj.conf
new file mode 100644
index 0000000000000..8bd97851e3684
--- /dev/null
+++ b/samples/bluetooth/peripheral_identity/prj.conf
@@ -0,0 +1,13 @@
+CONFIG_BT=y
+CONFIG_BT_PERIPHERAL=y
+CONFIG_BT_AUTO_PHY_UPDATE=n
+CONFIG_BT_PRIVACY=y
+
+CONFIG_BT_DEVICE_NAME="Zephyr Peripheral"
+CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
+
+CONFIG_BT_MAX_CONN=62
+CONFIG_BT_ID_MAX=62
+
+# CONFIG_BT_SMP=y
+# CONFIG_BT_MAX_PAIRED=62
diff --git a/samples/bluetooth/peripheral_identity/sample.yaml b/samples/bluetooth/peripheral_identity/sample.yaml
new file mode 100644
index 0000000000000..2ad924c725c88
--- /dev/null
+++ b/samples/bluetooth/peripheral_identity/sample.yaml
@@ -0,0 +1,8 @@
+sample:
+ description: TBD
+ name: TBD
+tests:
+ sample.bluetooth.peripheral_identity:
+ harness: bluetooth
+ platform_allow: qemu_cortex_m3 qemu_x86 nrf52840dk_nrf52840
+ tags: bluetooth
diff --git a/samples/bluetooth/peripheral_identity/src/main.c b/samples/bluetooth/peripheral_identity/src/main.c
new file mode 100644
index 0000000000000..9f3216e26f1bc
--- /dev/null
+++ b/samples/bluetooth/peripheral_identity/src/main.c
@@ -0,0 +1,14 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+int init_peripheral(void);
+
+void main(void)
+{
+ (void)init_peripheral();
+}
diff --git a/samples/bluetooth/peripheral_identity/src/peripheral_identity.c b/samples/bluetooth/peripheral_identity/src/peripheral_identity.c
new file mode 100644
index 0000000000000..94898ff53186a
--- /dev/null
+++ b/samples/bluetooth/peripheral_identity/src/peripheral_identity.c
@@ -0,0 +1,246 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+
+#include
+#include
+
+static struct k_work work_adv_start;
+static uint8_t volatile conn_count;
+static uint8_t id_current;
+
+static const struct bt_data ad[] = {
+ BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+};
+
+static void adv_start(struct k_work *work)
+{
+ struct bt_le_adv_param adv_param = {
+ .id = BT_ID_DEFAULT,
+ .sid = 0,
+ .secondary_max_skip = 0,
+ .options = (BT_LE_ADV_OPT_CONNECTABLE |
+ BT_LE_ADV_OPT_USE_NAME |
+ BT_LE_ADV_OPT_ONE_TIME),
+ .interval_min = 0x0020, /* 20 ms */
+ .interval_max = 0x0020, /* 20 ms */
+ .peer = NULL,
+ };
+ size_t id_count = 0xFF;
+ int err;
+
+ bt_id_get(NULL, &id_count);
+ if (id_current == id_count) {
+ int id;
+
+ id = bt_id_create(NULL, NULL);
+ if (id < 0) {
+ printk("Create id failed (%d)\n", id);
+ } else {
+ printk("New id: %d\n", id);
+ }
+ }
+
+ printk("Using current id: %u\n", id_current);
+ adv_param.id = id_current;
+
+ err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), NULL, 0);
+ if (err) {
+ printk("Advertising failed to start (err %d)\n", err);
+ return;
+ }
+
+ id_current++;
+ if (id_current == CONFIG_BT_MAX_CONN) {
+ id_current = 0;
+ }
+
+ printk("Advertising successfully started\n");
+}
+
+static void connected(struct bt_conn *conn, uint8_t err)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ if (err) {
+ printk("Connection failed (err 0x%02x)\n", err);
+ return;
+ }
+
+ conn_count++;
+ if (conn_count < CONFIG_BT_MAX_CONN) {
+ k_work_submit(&work_adv_start);
+ }
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("Connected (%u): %s\n", conn_count, addr);
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("Disconnected %s (reason 0x%02x)\n", addr, reason);
+
+ if (conn_count == CONFIG_BT_MAX_CONN) {
+ k_work_submit(&work_adv_start);
+ }
+ conn_count--;
+}
+
+static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("LE conn param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
+ addr, param->interval_min, param->interval_max, param->latency,
+ param->timeout);
+
+ return true;
+}
+
+static void le_param_updated(struct bt_conn *conn, uint16_t interval,
+ uint16_t latency, uint16_t timeout)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("LE conn param updated: %s int 0x%04x lat %d to %d\n",
+ addr, interval, latency, timeout);
+}
+
+#if defined(CONFIG_BT_SMP)
+static void security_changed(struct bt_conn *conn, bt_security_t level,
+ enum bt_security_err err)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ if (!err) {
+ printk("Security changed: %s level %u\n", addr, level);
+ } else {
+ printk("Security failed: %s level %u err %d\n", addr, level,
+ err);
+ }
+}
+
+static void auth_cancel(struct bt_conn *conn)
+{
+ char addr[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+ printk("Pairing cancelled: %s\n", addr);
+}
+
+static struct bt_conn_auth_cb auth_callbacks = {
+ .cancel = auth_cancel,
+};
+#endif /* CONFIG_BT_SMP */
+
+static struct bt_conn_cb conn_callbacks = {
+ .connected = connected,
+ .disconnected = disconnected,
+ .le_param_req = le_param_req,
+ .le_param_updated = le_param_updated,
+#if defined(CONFIG_BT_SMP)
+ .security_changed = security_changed,
+#endif /* CONFIG_BT_SMP */
+};
+
+#if defined(CONFIG_BT_OBSERVER)
+#define BT_LE_SCAN_PASSIVE_ALLOW_DUPILCATES \
+ BT_LE_SCAN_PARAM(BT_LE_SCAN_TYPE_PASSIVE, \
+ BT_LE_SCAN_OPT_NONE, \
+ BT_GAP_SCAN_FAST_INTERVAL, \
+ BT_GAP_SCAN_FAST_INTERVAL)
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+ struct net_buf_simple *ad)
+{
+ char addr_str[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
+ printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
+}
+#endif /* CONFIG_BT_OBSERVER */
+
+int init_peripheral(void)
+{
+ size_t id_count;
+ int err;
+
+ err = bt_enable(NULL);
+ if (err) {
+ printk("Bluetooth init failed (err %d)\n", err);
+ return err;
+ }
+
+ bt_conn_cb_register(&conn_callbacks);
+
+#if defined(CONFIG_BT_SMP)
+ bt_conn_auth_cb_register(&auth_callbacks);
+#endif /* CONFIG_BT_SMP */
+
+ printk("Bluetooth initialized\n");
+
+#if defined(CONFIG_BT_OBSERVER)
+ printk("Start continuous passive scanning...");
+ err = bt_le_scan_start(BT_LE_SCAN_PASSIVE_ALLOW_DUPILCATES,
+ device_found);
+ if (err) {
+ printk("Scan start failed (%d).\n", err);
+ return err;
+ }
+ printk("success.\n");
+#endif /* CONFIG_BT_OBSERVER */
+
+ k_work_init(&work_adv_start, adv_start);
+ k_work_submit(&work_adv_start);
+
+ /* wait for connection attempts on all identities */
+ do {
+ k_sleep(K_MSEC(100));
+
+ id_count = 0xFF;
+ bt_id_get(NULL, &id_count);
+ } while (id_count != CONFIG_BT_MAX_CONN);
+
+ /* rotate identities so reconnections are attempted in case of any
+ * disconnections
+ */
+ while (1) {
+ k_sleep(K_SECONDS(1));
+
+ if (conn_count == CONFIG_BT_MAX_CONN) {
+ break;
+ }
+
+ printk("Stop advertising...\n");
+ err = bt_le_adv_stop();
+ if (err) {
+ printk("Failed to stop advertising (%d)\n", err);
+
+ return err;
+ }
+
+ k_work_submit(&work_adv_start);
+ }
+
+ return 0;
+}
diff --git a/samples/net/sockets/can/boards/native_posix.conf b/samples/net/sockets/can/boards/native_posix.conf
new file mode 100644
index 0000000000000..e3f7d0a941002
--- /dev/null
+++ b/samples/net/sockets/can/boards/native_posix.conf
@@ -0,0 +1,2 @@
+CONFIG_CAN_NATIVE_POSIX=y
+CONFIG_ETH_NATIVE_POSIX=n
diff --git a/scripts/footprint/fpdiff.py b/scripts/footprint/fpdiff.py
new file mode 100755
index 0000000000000..3c4172b1d85ef
--- /dev/null
+++ b/scripts/footprint/fpdiff.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# A script to diff between two ram or rom reports generated by
+# size_report. When you call call the ram_report or rom_report targets you
+# end up with a json file in the build directory that can be used as input
+# for this script.
+
+# The output shows which symbols insreased and which decreased in size and
+# also tracked added/remove symbols as well.
+
+# Example:
+# ./scripts/footprint/fpdiff.py ram1.json ram2.json
+
+from anytree.importer import DictImporter
+from anytree import PreOrderIter
+from anytree.search import find
+
+from colorama import Fore
+import json
+import argparse
+
+importer = DictImporter()
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Compare footprint sizes of two builds.")
+ parser.add_argument("file1", help="First file")
+ parser.add_argument("file2", help="Second file")
+
+ return parser.parse_args()
+
+def main():
+ args = parse_args()
+
+ with open(args.file1, "r") as f:
+ data = json.load(f)
+ root1 = importer.import_(data['symbols'])
+
+ with open(args.file2, "r") as f:
+ data = json.load(f)
+ root2 = importer.import_(data['symbols'])
+
+ for node in PreOrderIter(root1):
+ # pylint: disable=undefined-loop-variable
+ n = find(root2, lambda node2: node2.identifier == node.identifier)
+ if n:
+ if n.size != node.size:
+ diff = n.size - node.size
+ if diff == 0:
+ continue
+ if not n.children or not n.parent:
+ if diff < 0:
+ print(f"{n.identifier} -> {Fore.GREEN}{diff}{Fore.RESET}")
+ else:
+ print(f"{n.identifier} -> {Fore.RED}+{diff}{Fore.RESET}")
+
+ else:
+ if not node.children:
+ print(f"{node.identifier} ({Fore.GREEN}-{node.size}{Fore.RESET}) disappeared.")
+
+ for node in PreOrderIter(root2):
+ n = find(root1, lambda node2: node2.identifier == node.identifier)
+ if not n:
+ if not node.children and node.size != 0:
+ print(f"{node.identifier} ({Fore.RED}+{node.size}{Fore.RESET}) is new.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/footprint/plan.txt b/scripts/footprint/plan.txt
new file mode 100644
index 0000000000000..6125e4e2be26a
--- /dev/null
+++ b/scripts/footprint/plan.txt
@@ -0,0 +1,10 @@
+footprints,default,frdm_k64f,tests/benchmarks/footprints,
+footprints,userspace,frdm_k64f,tests/benchmarks/footprints,-DCONF_FILE=prj_userspace.conf
+footprints,default,disco_l475_iot1,tests/benchmarks/footprints,
+footprints,userspace,disco_l475_iot1,tests/benchmarks/footprints,-DCONF_FILE=prj_userspace.conf
+footprints,default,nrf5340dk_nrf5340_cpuapp,tests/benchmarks/footprints,
+footprints,default,nrf51dk_nrf51422,tests/benchmarks/footprints,
+footprints,default,altera_max10,tests/benchmarks/footprints,
+footprints,default,hifive1_revb,tests/benchmarks/footprints,
+footprints,default,ehl_crb,tests/benchmarks/footprints,
+footprints,userspace,ehl_crb,tests/benchmarks/footprints,-DCONF_FILE=prj_userspace.conf
diff --git a/scripts/footprint/size_report b/scripts/footprint/size_report
index 884e06ad9e5ef..d767c0afd0455 100755
--- a/scripts/footprint/size_report
+++ b/scripts/footprint/size_report
@@ -557,7 +557,7 @@ def generate_any_tree(symbol_dict, total_size, path_prefix):
"""
Generate a symbol tree for output.
"""
- root = TreeNode('Symbols', "root")
+ root = TreeNode('Root', "root")
node_no_paths = TreeNode('(no paths)', ":", parent=root)
if Path(path_prefix) == Path(args.zephyrbase):
@@ -656,13 +656,12 @@ def generate_any_tree(symbol_dict, total_size, path_prefix):
root.children = children
- # Root node doesn't have sum of symbol size. So sum them up.
- root.size = sum_node_children_size(root)
+ root.size = total_size
# Need to account for code and data where there are not emitted
# symbols associated with them.
node_hidden_syms = TreeNode('(hidden)', "(hidden)", parent=root)
- node_hidden_syms.size = total_size - root.size
+ node_hidden_syms.size = root.size - sum_node_children_size(root)
return root
@@ -711,11 +710,13 @@ def parse_args():
help="Zephyr ELF binary")
parser.add_argument("-z", "--zephyrbase", required=True,
help="Zephyr base path")
+ parser.add_argument("-q", "--quiet", action="store_true",
+ help="Do not output anything on the screen.")
parser.add_argument("-o", "--output", required=True,
help="Output path")
parser.add_argument("-w", "--workspace", default=None,
help="Workspace path (Usually the same as WEST_TOPDIR)")
- parser.add_argument("target", choices=['rom', 'ram'])
+ parser.add_argument("target", choices=['rom', 'ram', 'all'])
parser.add_argument("-d", "--depth", dest="depth",
type=int, default=None,
help="How deep should we go into the tree",
@@ -736,55 +737,64 @@ def main():
init()
assert os.path.exists(args.kernel), "{0} does not exist.".format(args.kernel)
+ if args.target == 'ram':
+ targets = ['ram']
+ elif args.target == 'rom':
+ targets = ['rom']
+ elif args.target == 'all':
+ targets = ['rom', 'ram']
- elf = ELFFile(open(args.kernel, "rb"))
+ for t in targets:
- assert elf.has_dwarf_info(), "ELF file has no DWARF information"
+ elf = ELFFile(open(args.kernel, "rb"))
- set_global_machine_arch(elf.get_machine_arch())
+ assert elf.has_dwarf_info(), "ELF file has no DWARF information"
- addr_ranges = get_section_ranges(elf)
+ set_global_machine_arch(elf.get_machine_arch())
- symbols = get_symbols(elf, addr_ranges)
+ addr_ranges = get_section_ranges(elf)
- for sym in symbols['unassigned'].values():
- print("WARN: Symbol '{0}' is not in RAM or ROM".format(sym['name']))
+ symbols = get_symbols(elf, addr_ranges)
- symbol_dict = None
- if args.target == 'rom':
- symbol_dict = symbols['rom']
- symsize = addr_ranges['rom_total_size']
- ranges = addr_ranges['rom']
- elif args.target == 'ram':
- symbol_dict = symbols['ram']
- symsize = addr_ranges['ram_total_size']
- ranges = addr_ranges['ram']
+ for sym in symbols['unassigned'].values():
+ print("WARN: Symbol '{0}' is not in RAM or ROM".format(sym['name']))
- if symbol_dict is not None:
- processed = {"mapped_symbols": set(),
- "mapped_addr": set(),
- "unmapped_symbols": set(symbol_dict.keys())}
+ symbol_dict = None
- do_simple_name_matching(elf, symbol_dict, processed)
- mark_address_aliases(symbol_dict, processed)
- do_address_range_matching(elf, symbol_dict, processed)
- mark_address_aliases(symbol_dict, processed)
- common_path_prefix = find_common_path_prefix(symbol_dict)
- set_root_path_for_unmapped_symbols(symbol_dict, ranges, processed)
+ if args.json:
+ jsonout = args.json
+ else:
+ jsonout = os.path.join(args.output, f'{t}.json')
- if args.verbose:
- for sym in processed['unmapped_symbols']:
- print("INFO: Unmapped symbol: {0}".format(sym))
+ symbol_dict = symbols[t]
+ symsize = addr_ranges[f'{t}_total_size']
+ ranges = addr_ranges[t]
- root = generate_any_tree(symbol_dict, symsize, common_path_prefix)
- print_any_tree(root, symsize, args.depth)
+ if symbol_dict is not None:
+ processed = {"mapped_symbols": set(),
+ "mapped_addr": set(),
+ "unmapped_symbols": set(symbol_dict.keys())}
+
+ do_simple_name_matching(elf, symbol_dict, processed)
+ mark_address_aliases(symbol_dict, processed)
+ do_address_range_matching(elf, symbol_dict, processed)
+ mark_address_aliases(symbol_dict, processed)
+ common_path_prefix = find_common_path_prefix(symbol_dict)
+ set_root_path_for_unmapped_symbols(symbol_dict, ranges, processed)
+
+ if args.verbose:
+ for sym in processed['unmapped_symbols']:
+ print("INFO: Unmapped symbol: {0}".format(sym))
+
+ root = generate_any_tree(symbol_dict, symsize, common_path_prefix)
+ if not args.quiet:
+ print_any_tree(root, symsize, args.depth)
- if args.json:
exporter = DictExporter()
data = dict()
data["symbols"] = exporter.export(root)
data["total_size"] = symsize
- with open(args.json, "w") as fp:
+ with open(jsonout, "w") as fp:
json.dump(data, fp, indent=4)
diff --git a/scripts/footprint/track.py b/scripts/footprint/track.py
new file mode 100755
index 0000000000000..86e76bbf51767
--- /dev/null
+++ b/scripts/footprint/track.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import csv
+import subprocess
+from git import Git
+import pathlib
+import shutil
+import argparse
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Generate footprint data based on a predefined plan.")
+ parser.add_argument("-p", "--plan", help="Path of test plan", required=True)
+
+ return parser.parse_args()
+
+def main():
+ args = parse_args()
+ g = Git(".")
+ version = g.describe("--abbrev=12")
+ pathlib.Path(f'footprint_data/{version}').mkdir(exist_ok=True, parents=True)
+
+ with open(args.plan) as csvfile:
+ csvreader = csv.reader(csvfile)
+ for row in csvreader:
+ name=row[0]
+ feature=row[1]
+ board=row[2]
+ app=row[3]
+ options=row[4]
+
+ cmd = ['west',
+ 'build',
+ '-d',
+ f'out/{name}/{feature}/{board}',
+ '-b',
+ board,
+ f'{app}',
+ '-t',
+ 'footprint']
+
+ if options != '':
+ cmd += ['--', f'{options}']
+
+ print(" ".join(cmd))
+
+
+ try:
+ subprocess.check_output(cmd, stderr=subprocess.STDOUT, timeout=120, universal_newlines=True)
+ print("Copying files...")
+ pathlib.Path(f'footprint_data/{version}/{name}/{feature}/{board}').mkdir(parents=True, exist_ok=True)
+
+ shutil.copy(f'out/{name}/{feature}/{board}/ram.json', f'footprint_data/{version}/{name}/{feature}/{board}')
+ shutil.copy(f'out/{name}/{feature}/{board}/rom.json', f'footprint_data/{version}/{name}/{feature}/{board}')
+ except subprocess.CalledProcessError as exc:
+ print("Status : FAIL", exc.returncode, exc.output)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/footprint/upload_data.py b/scripts/footprint/upload_data.py
new file mode 100755
index 0000000000000..0084656b1ef89
--- /dev/null
+++ b/scripts/footprint/upload_data.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 Intel Corporation
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from anytree.importer import DictImporter
+from anytree import PreOrderIter
+from anytree.search import find
+importer = DictImporter()
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
+import os
+import json
+from git import Repo
+from git.exc import BadName
+
+from influxdb import InfluxDBClient
+import glob
+import argparse
+from tabulate import tabulate
+
+TODAY = datetime.utcnow()
+two_mon_rel = relativedelta(months=4)
+
+influx_dsn = 'influxdb://localhost:8086/footprint_tracking'
+
+def create_event(data, board, feature, commit, current_time, typ, application):
+ footprint_data = []
+ client = InfluxDBClient.from_dsn(influx_dsn)
+ client.create_database('footprint_tracking')
+ for d in data.keys():
+ footprint_data.append({
+ "measurement": d,
+ "tags": {
+ "board": board,
+ "commit": commit,
+ "application": application,
+ "type": typ,
+ "feature": feature
+ },
+ "time": current_time,
+ "fields": {
+ "value": data[d]
+ }
+ })
+
+ client.write_points(footprint_data, time_precision='s', database='footprint_tracking')
+
+
+def parse_args():
+ global args
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+
+ parser.add_argument("-d", "--data", help="Data Directory")
+ parser.add_argument("-y", "--dryrun", action="store_true", help="Dry run, do not upload to database")
+ parser.add_argument("-z", "--zephyr-base", help="Zephyr tree")
+ parser.add_argument("-f", "--file", help="JSON file with footprint data")
+ args = parser.parse_args()
+
+
+def parse_file(json_file):
+
+ with open(json_file, "r") as fp:
+ contents = json.load(fp)
+ root = importer.import_(contents['symbols'])
+
+ zr = find(root, lambda node: node.name == 'ZEPHYR_BASE')
+ ws = find(root, lambda node: node.name == 'WORKSPACE')
+
+ data = {}
+ if zr and ws:
+ trees = [zr, ws]
+ else:
+ trees = [root]
+
+ for node in PreOrderIter(root, maxlevel=2):
+ if node.name not in ['WORKSPACE', 'ZEPHYR_BASE']:
+ if node.name in ['Root', 'Symbols']:
+ data['all'] = node.size
+ else:
+ data[node.name] = node.size
+
+ for t in trees:
+ root = t.name
+ for node in PreOrderIter(t, maxlevel=2):
+ if node.name == root:
+ continue
+ comp = node.name
+ if comp in ['Root', 'Symbols']:
+ data['all'] = node.size
+ else:
+ data[comp] = node.size
+
+ return data
+
+def process_files(data_dir, zephyr_base, dry_run):
+ repo = Repo(zephyr_base)
+
+ for hash in os.listdir(f'{data_dir}'):
+ if not dry_run:
+ client = InfluxDBClient.from_dsn(influx_dsn)
+ result = client.query(f"select * from kernel where commit = '{hash}';")
+ if result:
+ print(f"Skipping {hash}...")
+ continue
+ print(f"Importing {hash}...")
+ for file in glob.glob(f"{args.data}/{hash}/**/*json", recursive=True):
+ file_data = file.split("/")
+ json_file = os.path.basename(file)
+ if 'ram' in json_file:
+ typ = 'ram'
+ else:
+ typ = 'rom'
+ commit = file_data[1]
+ app = file_data[2]
+ feature = file_data[3]
+ board = file_data[4]
+
+ data = parse_file(file)
+
+ try:
+ gitcommit = repo.commit(f'{commit}')
+ current_time = gitcommit.committed_datetime
+ except BadName:
+ cidx = commit.find('-g') + 2
+ gitcommit = repo.commit(f'{commit[cidx:]}')
+ current_time = gitcommit.committed_datetime
+
+ print(current_time)
+
+ if not dry_run:
+ create_event(data, board, feature, commit, current_time, typ, app)
+
+def main():
+ parse_args()
+
+ if args.data and args.zephyr_base:
+ process_files(args.data, args.zephyr_base, args.dryrun)
+
+ if args.file:
+ data = parse_file(args.file)
+ items = []
+ for component,value in data.items():
+ items.append([component,value])
+
+ table = tabulate(items, headers=['Component', 'Size'], tablefmt='orgtbl')
+ print(table)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/soc/arm/microchip_mec/common/soc_pcr.h b/soc/arm/microchip_mec/common/soc_pcr.h
new file mode 100644
index 0000000000000..81ce966b8e145
--- /dev/null
+++ b/soc/arm/microchip_mec/common/soc_pcr.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 Microchip Technology Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _SOC_MCHP_PCR_H_
+#define _SOC_MCHP_PCR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* slp_idx = [0, 4], bitpos = [0, 31] refer above */
+#define MCHP_XEC_PCR_SCR_ENCODE(slp_idx, bitpos) \
+ (((uint16_t)(slp_idx) & 0x7u) | (((uint16_t)bitpos & 0x1fu) << 3))
+
+#define MCHP_XEC_PCR_SCR_GET_IDX(e) ((e) & 0x7u)
+#define MCHP_XEC_PCR_SCR_GET_BITPOS(e) (((e) & 0xf8u) >> 3)
+
+/* cpu clock divider */
+#define MCHP_XEC_CLK_CPU_MASK GENMASK(7, 0)
+#define MCHP_XEC_CLK_CPU_CLK_DIV_1 1u
+#define MCHP_XEC_CLK_CPU_CLK_DIV_2 2u
+#define MCHP_XEC_CLK_CPU_CLK_DIV_4 4u
+#define MCHP_XEC_CLK_CPU_CLK_DIV_8 8u
+#define MCHP_XEC_CLK_CPU_CLK_DIV_16 16u
+#define MCHP_XEC_CLK_CPU_CLK_DIV_48 48u
+
+/* slow clock divider */
+#define MCHP_XEC_CLK_SLOW_MASK GENMASK(8, 0)
+#define MCHP_XEC_CLK_SLOW_CLK_DIV_100K 480u
+
+#define MCHP_XEC_CLK_SRC_POS 24
+#define MCHP_XEC_CLK_SRC_MASK GENMASK(31, 24)
+
+#define MCHP_XEC_CLK_SRC_GET(n) \
+ (((n) & MCHP_XEC_CLK_SRC_MASK) >> MCHP_XEC_CLK_SRC_POS)
+
+#define MCHP_XEC_CLK_SRC_SET(v, c) (((v) & ~MCHP_XEC_CLK_SRC_MASK) |\
+ (((c) << MCHP_XEC_CLK_SRC_POS) & MCHP_XEC_CLK_SRC_MASK))
+
+/*
+ * b[31:24] = clock source
+ * b[23:0] = clock source specific format
+ */
+struct mchp_xec_pcr_clk_ctrl {
+ uint32_t pcr_info;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SOC_MCHP_PCR_H_ */
diff --git a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.mec172xnsz b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.mec172xnsz
index f8fc88d43abd0..ffe67501aee57 100644
--- a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.mec172xnsz
+++ b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.mec172xnsz
@@ -8,4 +8,8 @@ if SOC_MEC172X_NSZ
config SOC
default "mec172xnsz"
+config UART_NS16550
+ default y
+ depends on SERIAL
+
endif # SOC_MEC172X_NSZ
diff --git a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series
index 036eb2169f3ef..c783649418fce 100644
--- a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series
+++ b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series
@@ -19,4 +19,7 @@ source "soc/arm/microchip_mec/mec172x/Kconfig.defconfig.mec172x*"
config CORTEX_M_SYSTICK
default y
+config CLOCK_CONTROL_MCHP_XEC
+ default y
+
endif # SOC_SERIES_MEC172X
diff --git a/soc/arm/microchip_mec/mec172x/soc.h b/soc/arm/microchip_mec/mec172x/soc.h
index 675a16aeaadb6..0523753c59f1c 100644
--- a/soc/arm/microchip_mec/mec172x/soc.h
+++ b/soc/arm/microchip_mec/mec172x/soc.h
@@ -58,6 +58,7 @@
/* common SoC API */
#include "../common/soc_gpio.h"
+#include "../common/soc_pcr.h"
#include "../common/soc_pins.h"
#include "../common/soc_espi_channels.h"
#include "../common/soc_espi_saf.h"
diff --git a/soc/arm/nxp_imx/rt6xx/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt6xx/Kconfig.defconfig.series
index d19f4db44fff6..2fef615b4e0df 100644
--- a/soc/arm/nxp_imx/rt6xx/Kconfig.defconfig.series
+++ b/soc/arm/nxp_imx/rt6xx/Kconfig.defconfig.series
@@ -23,6 +23,10 @@ config FLASH_SIZE
config FLASH_BASE_ADDRESS
default $(dt_node_reg_addr_hex,/soc/peripheral@50000000/spi@134000,1)
+config ENTROPY_MCUX_TRNG
+ default y if HAS_MCUX_TRNG
+ depends on ENTROPY_GENERATOR
+
source "soc/arm/nxp_imx/rt6xx/Kconfig.defconfig.mimxrt6*"
endif # SOC_SERIES_MIMXRT6XX
diff --git a/soc/arm/nxp_imx/rt6xx/Kconfig.soc b/soc/arm/nxp_imx/rt6xx/Kconfig.soc
index d077fbbeef5ea..f4859fc699b14 100644
--- a/soc/arm/nxp_imx/rt6xx/Kconfig.soc
+++ b/soc/arm/nxp_imx/rt6xx/Kconfig.soc
@@ -23,6 +23,7 @@ config SOC_MIMXRT685S_CM33
select HAS_MCUX_LPC_DMA
select HAS_MCUX_OS_TIMER
select HAS_MCUX_LPC_RTC
+ select HAS_MCUX_TRNG
select INIT_SYS_PLL
endchoice
diff --git a/soc/arm/st_stm32/stm32wb/power.c b/soc/arm/st_stm32/stm32wb/power.c
index b9d5086a2928a..6d08ac2104dd5 100644
--- a/soc/arm/st_stm32/stm32wb/power.c
+++ b/soc/arm/st_stm32/stm32wb/power.c
@@ -14,10 +14,28 @@
#include
#include
#include
+#include "stm32_hsem.h"
#include
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
+/*
+ * @brief Switch the system clock on HSI
+ * @param none
+ * @retval none
+ */
+static void switch_on_hsi(void)
+{
+ LL_RCC_HSI_Enable();
+ while (!LL_RCC_HSI_IsReady()) {
+ }
+
+ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
+ LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI);
+ while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
+ }
+}
+
/* Invoke Low Power/System Off specific Tasks */
void pm_power_state_set(struct pm_state_info info)
{
@@ -26,12 +44,28 @@ void pm_power_state_set(struct pm_state_info info)
return;
}
+ /* Implementation of STM32 AN5289 algorithm to enter/exit lowpower */
+ z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_WAIT_FOREVER);
+ if (!LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID)) {
+ if (LL_PWR_IsActiveFlag_C2DS()) {
+ /* Release ENTRY_STOP_MODE semaphore */
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
+
+ /* The switch on HSI before entering Stop Mode is required */
+ switch_on_hsi();
+ }
+ } else {
+ /* The switch on HSI before entering Stop Mode is required */
+ switch_on_hsi();
+ }
+
switch (info.substate_id) {
case 1: /* this corresponds to the STOP0 mode: */
/* ensure HSI is the wake-up system clock */
LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
/* enter STOP0 mode */
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0);
+ z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
LL_LPM_EnableDeepSleep();
/* enter SLEEP mode : WFE or WFI */
k_cpu_idle();
@@ -41,6 +75,7 @@ void pm_power_state_set(struct pm_state_info info)
LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
/* enter STOP1 mode */
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1);
+ z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
LL_LPM_EnableDeepSleep();
/* enter SLEEP mode : WFE or WFI */
k_cpu_idle();
@@ -53,11 +88,14 @@ void pm_power_state_set(struct pm_state_info info)
#endif /* PWR_CR1_RRSTP */
/* enter STOP2 mode */
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
+ z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
LL_LPM_EnableDeepSleep();
/* enter SLEEP mode : WFE or WFI */
k_cpu_idle();
break;
default:
+ /* Release RCC semaphore */
+ z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
LOG_DBG("Unsupported power substate-id %u", info.substate_id);
break;
}
@@ -66,6 +104,11 @@ void pm_power_state_set(struct pm_state_info info)
/* Handle SOC specific activity after Low Power Mode Exit */
void pm_power_state_exit_post_ops(struct pm_state_info info)
{
+ /* Implementation of STM32 AN5289 algorithm to enter/exit lowpower */
+ /* Release ENTRY_STOP_MODE semaphore */
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
+ z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_WAIT_FOREVER);
+
if (info.state != PM_STATE_SUSPEND_TO_IDLE) {
LOG_DBG("Unsupported power state %u", info.state);
} else {
@@ -87,6 +130,9 @@ void pm_power_state_exit_post_ops(struct pm_state_info info)
stm32_clock_control_init(NULL);
}
+ /* Release RCC semaphore */
+ z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
+
/*
* System is now in active mode.
* Reenable interrupts which were disabled
diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c b/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c
index 011567e991acf..59874db878230 100644
--- a/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c
+++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c
@@ -99,14 +99,8 @@ void pm_power_state_set(struct pm_state_info info)
break;
case PM_STATE_STANDBY:
- /* schedule the wakeup event */
- ClockP_start(ClockP_handle((ClockP_Struct *)
- &PowerCC26X2_module.clockObj));
-
/* go to standby mode */
Power_sleep(PowerCC26XX_STANDBY);
- ClockP_stop(ClockP_handle((ClockP_Struct *)
- &PowerCC26X2_module.clockObj));
break;
case PM_STATE_SUSPEND_TO_RAM:
__fallthrough;
diff --git a/soc/riscv/riscv-privilege/telink_b91/CMakeLists.txt b/soc/riscv/riscv-privilege/telink_b91/CMakeLists.txt
new file mode 100644
index 0000000000000..a116969d93d65
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+zephyr_sources(
+ start.S
+ soc_irq.S
+ soc.c
+)
+
+# Force using BFD-LD
+zephyr_ld_options(-fuse-ld=bfd)
+
+# Set compile options
+zephyr_compile_options_ifdef(CONFIG_TELINK_B91_HWDSP -mext-dsp)
+zephyr_compile_options(-mno-relax)
diff --git a/soc/riscv/riscv-privilege/telink_b91/Kconfig.defconfig.series b/soc/riscv/riscv-privilege/telink_b91/Kconfig.defconfig.series
new file mode 100644
index 0000000000000..7f2c12d6b480a
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/Kconfig.defconfig.series
@@ -0,0 +1,46 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+if SOC_SERIES_RISCV_TELINK_B91
+
+config SOC_SERIES
+ string
+ default "telink_b91"
+
+config SYS_CLOCK_HW_CYCLES_PER_SEC
+ int
+ default 32000
+
+config RISCV_SOC_INTERRUPT_INIT
+ bool
+ default y
+
+config RISCV_HAS_CPU_IDLE
+ bool
+ default y
+
+config RISCV_HAS_PLIC
+ bool
+ default y
+
+config NUM_IRQS
+ int
+ default 64
+
+config XIP
+ bool
+ default n
+
+config MAIN_STACK_SIZE
+ int
+ default 2048
+
+config IDLE_STACK_SIZE
+ int
+ default 1536
+
+config TEST_EXTRA_STACKSIZE
+ int
+ default 1024
+
+endif # SOC_SERIES_RISCV_TELINK_B91
diff --git a/soc/riscv/riscv-privilege/telink_b91/Kconfig.series b/soc/riscv/riscv-privilege/telink_b91/Kconfig.series
new file mode 100644
index 0000000000000..ba9aba0840e71
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/Kconfig.series
@@ -0,0 +1,10 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+config SOC_SERIES_RISCV_TELINK_B91
+ bool "Telink B91 SoC Implementation"
+ select RISCV
+ select SOC_FAMILY_RISCV_PRIVILEGE
+ select HAS_TELINK_DRIVERS
+ help
+ Enable support for Telink B91 SoC
diff --git a/soc/riscv/riscv-privilege/telink_b91/Kconfig.soc b/soc/riscv/riscv-privilege/telink_b91/Kconfig.soc
new file mode 100644
index 0000000000000..973bef47a1931
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/Kconfig.soc
@@ -0,0 +1,33 @@
+# Copyright (c) 2021 Telink Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+choice
+prompt "CPU Architecture of SoC"
+depends on SOC_SERIES_RISCV_TELINK_B91
+
+config B91_CPU_RISCV32
+ bool "RISCV32 CPU Architecture"
+
+endchoice
+
+config TELINK_B91_HWDSP
+ bool "Support Hardware DSP"
+ select RISCV_SOC_CONTEXT_SAVE
+ depends on SOC_SERIES_RISCV_TELINK_B91
+
+config TELINK_B91_PFT_ARCH
+ bool "Support performance throttling"
+ default y
+ select RISCV_SOC_CONTEXT_SAVE
+ depends on SOC_SERIES_RISCV_TELINK_B91
+
+choice
+prompt "Telink B91 SoC implementation"
+depends on SOC_SERIES_RISCV_TELINK_B91
+
+config SOC_RISCV_TELINK_B91
+ bool "Telink B91 SoC implementation"
+ select ATOMIC_OPERATIONS_BUILTIN
+ select CPU_HAS_FPU
+
+endchoice
diff --git a/soc/riscv/riscv-privilege/telink_b91/linker.ld b/soc/riscv/riscv-privilege/telink_b91/linker.ld
new file mode 100644
index 0000000000000..03aecd466775f
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/linker.ld
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @brief Linker script for the Telink B91 SoC
+ */
+
+#include
+#include
+#include
+
+MEMORY
+{
+ ROM_INIT (rx) : ORIGIN = DT_REG_ADDR(DT_CHOSEN(zephyr_flash)), LENGTH = DT_REG_SIZE(DT_CHOSEN(zephyr_flash))
+ RAM_ILM (rwx) : ORIGIN = DT_REG_ADDR(DT_NODELABEL(ram_ilm)), LENGTH = DT_REG_SIZE(DT_NODELABEL(ram_ilm))
+}
+
+SECTIONS
+{
+ SECTION_PROLOGUE(vector,,)
+ {
+ . = ALIGN(4);
+ KEEP(*(.init.*))
+ } GROUP_LINK_IN(ROM_INIT)
+}
+
+#include
+
+SECTIONS
+{
+ SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,)
+ {
+ . = ALIGN(8);
+ PROVIDE (__global_pointer$ = __data_ram_start + 0x800);
+ } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
+
+ SECTION_DATA_PROLOGUE(retention_data,,)
+ {
+ . = ALIGN(8);
+ *(.retention_data)
+ *(".retention_data.*")
+
+ PROVIDE (_RETENTION_DATA_VMA_END = .);
+ PROVIDE (_RETENTION_DATA_VMA_START = ADDR(retention_data));
+ PROVIDE (_RETENTION_DATA_LMA_START = LOADADDR(retention_data));
+ } GROUP_DATA_LINK_IN(RAM_ILM, ROMABLE_REGION)
+
+ SECTION_DATA_PROLOGUE(ram_code,,)
+ {
+ . = ALIGN(8);
+ *(.ram_code)
+ *(".ram_code.*")
+
+ PROVIDE (_RAMCODE_VMA_END = .);
+ PROVIDE (_RAMCODE_VMA_START = ADDR(ram_code));
+ PROVIDE (_RAMCODE_LMA_START = LOADADDR(ram_code));
+ } GROUP_DATA_LINK_IN(RAM_ILM, ROMABLE_REGION)
+}
diff --git a/soc/riscv/riscv-privilege/telink_b91/soc.c b/soc/riscv/riscv-privilege/telink_b91/soc.c
new file mode 100644
index 0000000000000..05735b68ee61b
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/soc.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "sys.h"
+#include "clock.h"
+#include
+
+/* Software reset defines */
+#define reg_reset REG_ADDR8(0x1401ef)
+#define SOFT_RESET 0x20u
+
+/* List of supported CCLK fregencies */
+#define CLK_16MHZ 16000000u
+#define CLK_24MHZ 24000000u
+#define CLK_32MHZ 32000000u
+#define CLK_48MHZ 48000000u
+#define CLK_64MHZ 64000000u
+#define CLK_96MHZ 96000000u
+
+/* Define 48 MHz and 96 MHz CCLK clock options (not present in HAL) */
+#define CCLK_64M_HCLK_32M_PCLK_16M clock_init(PLL_CLK_192M, \
+ PAD_PLL_DIV, \
+ PLL_DIV3_TO_CCLK, \
+ CCLK_DIV2_TO_HCLK, \
+ HCLK_DIV2_TO_PCLK, \
+ PLL_DIV4_TO_MSPI_CLK)
+
+#define CCLK_96M_HCLK_48M_PCLK_24M clock_init(PLL_CLK_192M, \
+ PAD_PLL_DIV, \
+ PLL_DIV2_TO_CCLK, \
+ CCLK_DIV2_TO_HCLK, \
+ HCLK_DIV2_TO_PCLK, \
+ PLL_DIV4_TO_MSPI_CLK)
+
+/* Power Mode value */
+#if DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 0
+ #define POWER_MODE LDO_1P4_LDO_1P8
+#elif DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 1
+ #define POWER_MODE DCDC_1P4_LDO_1P8
+#elif DT_ENUM_IDX(DT_NODELABEL(power), power_mode) == 2
+ #define POWER_MODE DCDC_1P4_DCDC_1P8
+#else
+ #error "Wrong value for power-mode parameter"
+#endif
+
+/* Vbat Type value */
+#if DT_ENUM_IDX(DT_NODELABEL(power), vbat_type) == 0
+ #define VBAT_TYPE VBAT_MAX_VALUE_LESS_THAN_3V6
+#elif DT_ENUM_IDX(DT_NODELABEL(power), vbat_type) == 1
+ #define VBAT_TYPE VBAT_MAX_VALUE_GREATER_THAN_3V6
+#else
+ #error "Wrong value for vbat-type parameter"
+#endif
+
+/* Check System Clock value. */
+#if ((DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_16MHZ) && \
+ (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_24MHZ) && \
+ (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_32MHZ) && \
+ (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_48MHZ) && \
+ (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_64MHZ) && \
+ (DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) != CLK_96MHZ))
+ #error "Unsupported clock-frequency. Supported values: 16, 24, 32, 48, 64 and 96 MHz"
+#endif
+
+/**
+ * @brief Perform basic initialization at boot.
+ *
+ * @return 0
+ */
+static int soc_b91_init(const struct device *arg)
+{
+ unsigned int cclk = DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency);
+
+ ARG_UNUSED(arg);
+
+ /* system init */
+ sys_init(POWER_MODE, VBAT_TYPE);
+
+ /* clocks init: CCLK, HCLK, PCLK */
+ switch (cclk) {
+ case CLK_16MHZ:
+ CCLK_16M_HCLK_16M_PCLK_16M;
+ break;
+
+ case CLK_24MHZ:
+ CCLK_24M_HCLK_24M_PCLK_24M;
+ break;
+
+ case CLK_32MHZ:
+ CCLK_32M_HCLK_32M_PCLK_16M;
+ break;
+
+ case CLK_48MHZ:
+ CCLK_48M_HCLK_48M_PCLK_24M;
+ break;
+
+ case CLK_64MHZ:
+ CCLK_64M_HCLK_32M_PCLK_16M;
+ break;
+
+ case CLK_96MHZ:
+ CCLK_96M_HCLK_48M_PCLK_24M;
+ break;
+ }
+
+ /* Init Machine Timer source clock: 32 KHz RC */
+ clock_32k_init(CLK_32K_RC);
+ clock_cal_32k_rc();
+
+ return 0;
+}
+
+/**
+ * @brief Reset the system.
+ */
+void sys_arch_reboot(int type)
+{
+ ARG_UNUSED(type);
+
+ reg_reset = SOFT_RESET;
+}
+
+SYS_INIT(soc_b91_init, PRE_KERNEL_1, 0);
diff --git a/soc/riscv/riscv-privilege/telink_b91/soc.h b/soc/riscv/riscv-privilege/telink_b91/soc.h
new file mode 100644
index 0000000000000..2f932c09d40ce
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/soc.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef RISCV_TELINK_B91_SOC_H
+#define RISCV_TELINK_B91_SOC_H
+
+#include
+#include
+
+/* Machine timer memory-mapped registers */
+#define RISCV_MTIME_BASE 0xE6000000
+#define RISCV_MTIMECMP_BASE 0xE6000008
+
+#endif /* RISCV_TELINK_B91_SOC_H */
diff --git a/soc/riscv/riscv-privilege/telink_b91/soc_context.h b/soc/riscv/riscv-privilege/telink_b91/soc_context.h
new file mode 100644
index 0000000000000..0f06686453988
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/soc_context.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef SOC_RISCV_TELINK_B91_SOC_CONTEXT_H
+#define SOC_RISCV_TELINK_B91_SOC_CONTEXT_H
+
+#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE
+
+/* Telink B91 specific registers. */
+#if defined(CONFIG_TELINK_B91_PFT_ARCH) && defined(__riscv_dsp)
+ #define SOC_ESF_MEMBERS \
+ uint32_t mxstatus; \
+ uint32_t ucode \
+
+ #define SOC_ESF_INIT \
+ 0xdeadbaad, \
+ 0xdeadbaad
+
+ #define SOC_ESF_THREAD_INIT(soc_context) \
+ (soc_context)->mxstatus = 0; \
+ (soc_context)->ucode = 0
+
+#elif defined(CONFIG_TELINK_B91_PFT_ARCH)
+ #define SOC_ESF_MEMBERS \
+ uint32_t mxstatus
+
+ #define SOC_ESF_INIT \
+ 0xdeadbaad
+
+ #define SOC_ESF_THREAD_INIT(soc_context) \
+ (soc_context)->mxstatus = 0
+
+#elif defined(__riscv_dsp)
+
+ #define SOC_ESF_MEMBERS \
+ uint32_t ucode
+
+ #define SOC_ESF_INIT \
+ 0xdeadbaad
+
+ #define SOC_ESF_THREAD_INIT(soc_context) \
+ (soc_context)->ucode = 0
+#endif
+
+#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */
+
+#endif /* SOC_RISCV_TELINK_B91_SOC_CONTEXT_H */
diff --git a/soc/riscv/riscv-privilege/telink_b91/soc_irq.S b/soc/riscv/riscv-privilege/telink_b91/soc_irq.S
new file mode 100644
index 0000000000000..abc9015b66be0
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/soc_irq.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+
+#include
+
+#define NDS_MXSTATUS 0x7C4
+
+/* Exports */
+#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE
+GTEXT(__soc_save_context)
+GTEXT(__soc_restore_context)
+#endif
+
+#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE
+
+SECTION_FUNC(exception.other, __soc_save_context)
+
+#ifdef CONFIG_TELINK_B91_PFT_ARCH
+ csrr t0, NDS_MXSTATUS
+#endif
+#ifdef __riscv_dsp
+ csrr t1, ucode
+#endif
+
+#ifdef CONFIG_TELINK_B91_PFT_ARCH
+ sw t0, __soc_esf_t_mxstatus_OFFSET(a0)
+#endif
+#ifdef __riscv_dsp
+ sw t1, __soc_esf_t_ucode_OFFSET(a0)
+#endif
+ ret
+
+SECTION_FUNC(exception.other, __soc_restore_context)
+
+#ifdef CONFIG_TELINK_B91_PFT_ARCH
+ lw t0, __soc_esf_t_mxstatus_OFFSET(a0)
+#endif
+#ifdef __riscv_dsp
+ lw t1, __soc_esf_t_ucode_OFFSET(a0)
+#endif
+
+#ifdef CONFIG_TELINK_B91_PFT_ARCH
+ csrw NDS_MXSTATUS, t0
+#endif
+#ifdef __riscv_dsp
+ csrw ucode, t1
+#endif
+ ret
+
+#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */
diff --git a/soc/riscv/riscv-privilege/telink_b91/soc_offsets.h b/soc/riscv/riscv-privilege/telink_b91/soc_offsets.h
new file mode 100644
index 0000000000000..8b48bceedfffa
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/soc_offsets.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef SOC_RISCV_TELINK_B91_SOC_OFFSETS_H
+#define SOC_RISCV_TELINK_B91_SOC_OFFSETS_H
+
+#ifdef CONFIG_RISCV_SOC_OFFSETS
+
+/* Telink B91 specific registers. */
+#if defined(CONFIG_TELINK_B91_PFT_ARCH) && defined(__riscv_dsp)
+ #define GEN_SOC_OFFSET_SYMS() \
+ GEN_OFFSET_SYM(soc_esf_t, mxstatus); \
+ GEN_OFFSET_SYM(soc_esf_t, ucode)
+
+#elif defined(CONFIG_TELINK_B91_PFT_ARCH)
+ #define GEN_SOC_OFFSET_SYMS() \
+ GEN_OFFSET_SYM(soc_esf_t, mxstatus)
+
+#elif defined(__riscv_dsp)
+ #define GEN_SOC_OFFSET_SYMS() \
+ GEN_OFFSET_SYM(soc_esf_t, ucode)
+
+#endif
+
+#endif /* CONFIG_RISCV_SOC_OFFSETS */
+
+#endif /* SOC_RISCV_TELINK_B91_SOC_OFFSETS_H*/
diff --git a/soc/riscv/riscv-privilege/telink_b91/start.S b/soc/riscv/riscv-privilege/telink_b91/start.S
new file mode 100644
index 0000000000000..a791d2eeae980
--- /dev/null
+++ b/soc/riscv/riscv-privilege/telink_b91/start.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define NDS_MCACHE_CTL 0x7CA
+#define NDS_MMISC_CTL 0x7D0
+
+#include
+
+ .option push
+ .option norelax
+ .org 0x0
+
+/* exports */
+GTEXT(entry)
+
+SECTION_FUNC(init, init)
+entry:
+
+ j start
+
+ .org 0x20
+ .word ('T'<<24 | 'L'<<16 | 'N'<<8 | 'K')
+
+ .org 0x26
+ .short (0x173B)
+
+ .option pop
+ .align 2
+
+start:
+
+ /* Enable I/D-Cache */
+ csrr t0, NDS_MCACHE_CTL
+ ori t0, t0, 1 #/I-Cache
+ ori t0, t0, 2 #/D-Cache
+ csrw NDS_MCACHE_CTL, t0
+ fence.i
+
+ /* Enable misaligned access and non-blocking load */
+ li t0, (1 << 8) | (1 << 6)
+ csrs NDS_MMISC_CTL, t0
+
+_RETENTION_DATA_INIT:
+ la t1, _RETENTION_DATA_LMA_START
+ la t2, _RETENTION_DATA_VMA_START
+ la t3, _RETENTION_DATA_VMA_END
+_RETENTION_DATA_INIT_BEGIN:
+ bleu t3, t2, _RAMCODE_INIT
+ lw t0, 0(t1)
+ sw t0, 0(t2)
+ addi t1, t1, 4
+ addi t2, t2, 4
+ j _RETENTION_DATA_INIT_BEGIN
+
+_RAMCODE_INIT:
+ la t1, _RAMCODE_LMA_START
+ la t2, _RAMCODE_VMA_START
+ la t3, _RAMCODE_VMA_END
+_RAMCODE_INIT_BEGIN:
+ bleu t3, t2, _START
+ lw t0, 0(t1)
+ sw t0, 0(t2)
+ addi t1, t1, 4
+ addi t2, t2, 4
+ j _RAMCODE_INIT_BEGIN
+
+_START:
+ j __start
diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig
index 2bd2248accef6..90cdc8a4f6eef 100644
--- a/subsys/bluetooth/host/Kconfig
+++ b/subsys/bluetooth/host/Kconfig
@@ -539,7 +539,7 @@ config BT_DEVICE_APPEARANCE
config BT_ID_MAX
int "Maximum number of local identities"
- range 1 10
+ range 1 64
default 1
help
Maximum number of supported local identity addresses. For most
diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c
index e295201b8d37b..cd17fd1ce67e4 100644
--- a/subsys/net/ip/net_pkt.c
+++ b/subsys/net/ip/net_pkt.c
@@ -55,7 +55,11 @@ LOG_MODULE_REGISTER(net_pkt, CONFIG_NET_PKT_LOG_LEVEL);
*/
#define MAX_IP_PROTO_LEN 8
#else
+#if defined(CONFIG_NET_ETHERNET_BRIDGE)
+#define MAX_IP_PROTO_LEN 0
+#else
#error "Either IPv6 or IPv4 needs to be selected."
+#endif /* ETHERNET_BRIDGE */
#endif /* SOCKETS_CAN */
#endif /* IPv4 */
#endif /* IPv6 */
@@ -1769,6 +1773,7 @@ static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_pkt)
net_pkt_set_priority(clone_pkt, net_pkt_priority(pkt));
net_pkt_set_orig_iface(clone_pkt, net_pkt_orig_iface(pkt));
net_pkt_set_captured(clone_pkt, net_pkt_is_captured(pkt));
+ net_pkt_set_l2_bridged(clone_pkt, net_pkt_is_l2_bridged(pkt));
if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
net_pkt_set_ipv4_ttl(clone_pkt, net_pkt_ipv4_ttl(pkt));
diff --git a/subsys/net/l2/ethernet/CMakeLists.txt b/subsys/net/l2/ethernet/CMakeLists.txt
index 7d8c4eb89abbf..9b13d0b2a48a8 100644
--- a/subsys/net/l2/ethernet/CMakeLists.txt
+++ b/subsys/net/l2/ethernet/CMakeLists.txt
@@ -12,6 +12,8 @@ zephyr_library_sources_ifdef(CONFIG_NET_L2_ETHERNET_MGMT ethernet_mgmt.c)
if(CONFIG_NET_NATIVE)
zephyr_library_sources_ifdef(CONFIG_NET_ARP arp.c)
zephyr_library_sources_ifdef(CONFIG_NET_STATISTICS_ETHERNET ethernet_stats.c)
+zephyr_library_sources_ifdef(CONFIG_NET_ETHERNET_BRIDGE bridge.c)
+zephyr_library_sources_ifdef(CONFIG_NET_ETHERNET_BRIDGE_SHELL bridge_shell.c)
if(CONFIG_NET_GPTP)
add_subdirectory(gptp)
diff --git a/subsys/net/l2/ethernet/Kconfig b/subsys/net/l2/ethernet/Kconfig
index 9fd0049de7aaa..ba930c631ff05 100644
--- a/subsys/net/l2/ethernet/Kconfig
+++ b/subsys/net/l2/ethernet/Kconfig
@@ -76,4 +76,36 @@ endif # NET_ARP
source "subsys/net/l2/ethernet/gptp/Kconfig"
source "subsys/net/l2/ethernet/lldp/Kconfig"
+config NET_ETHERNET_BRIDGE
+ bool "Ethernet Bridging support"
+ select NET_PROMISCUOUS_MODE
+ help
+ Enables Ethernet bridging where packets can be transparently
+ forwarded across interfaces registered to a bridge.
+
+if NET_ETHERNET_BRIDGE
+module = NET_ETHERNET_BRIDGE
+module-dep = NET_LOG
+module-str = Log level for Ethernet Bridging
+module-help = Enables Ethernet Bridge code to output debug messages.
+source "subsys/net/Kconfig.template.log_config.net"
+endif # NET_ETHERNET_BRIDGE
+
+config NET_ETHERNET_BRIDGE_SHELL
+ bool "Ethernet Bridging management shell"
+ depends on NET_ETHERNET_BRIDGE
+ select SHELL
+ help
+ Enables shell utility to manage bridge configuration interactively.
+
+config NET_ETHERNET_BRIDGE_DEFAULT
+ bool "Declare one bridge instance for shell usage"
+ depends on NET_ETHERNET_BRIDGE_SHELL
+ default y
+ help
+ If the bridge shell is the sole user of the bridge code then
+ it needs at least one bridge instance to be useful.
+ Say y if this is the case. If you only want to inspect
+ existing bridge instances then say n.
+
endif # NET_L2_ETHERNET
diff --git a/subsys/net/l2/ethernet/bridge.c b/subsys/net/l2/ethernet/bridge.c
new file mode 100644
index 0000000000000..2df15dba44a64
--- /dev/null
+++ b/subsys/net/l2/ethernet/bridge.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2021 BayLibre SAS
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+LOG_MODULE_REGISTER(net_eth_bridge, CONFIG_NET_ETHERNET_BRIDGE_LOG_LEVEL);
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "bridge.h"
+
+extern struct eth_bridge _eth_bridge_list_start[];
+extern struct eth_bridge _eth_bridge_list_end[];
+
+void net_eth_bridge_foreach(eth_bridge_cb_t cb, void *user_data)
+{
+ Z_STRUCT_SECTION_FOREACH(eth_bridge, br) {
+ cb(br, user_data);
+ }
+}
+
+int eth_bridge_get_index(struct eth_bridge *br)
+{
+ if (!(br >= _eth_bridge_list_start && br < _eth_bridge_list_end)) {
+ return -1;
+ }
+
+ return (br - _eth_bridge_list_start) + 1;
+}
+
+struct eth_bridge *eth_bridge_get_by_index(int index)
+{
+ if (index <= 0) {
+ return NULL;
+ }
+
+ if (&_eth_bridge_list_start[index - 1] >= _eth_bridge_list_end) {
+ NET_DBG("Index %d is too large", index);
+ return NULL;
+ }
+
+ return &_eth_bridge_list_start[index - 1];
+}
+
+int eth_bridge_iface_add(struct eth_bridge *br, struct net_if *iface)
+{
+ struct ethernet_context *ctx = net_if_l2_data(iface);
+
+ if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET) ||
+ !(net_eth_get_hw_capabilities(iface) & ETHERNET_PROMISC_MODE)) {
+ return -EINVAL;
+ }
+
+ k_mutex_lock(&br->lock, K_FOREVER);
+
+ if (ctx->bridge.instance != NULL) {
+ k_mutex_unlock(&br->lock);
+ return -EBUSY;
+ }
+
+ ctx->bridge.instance = br;
+ ctx->bridge.allow_tx = false;
+ sys_slist_append(&br->interfaces, &ctx->bridge.node);
+
+ k_mutex_unlock(&br->lock);
+
+ int ret = net_eth_promisc_mode(iface, true);
+
+ if (ret != 0) {
+ NET_DBG("iface %p promiscuous mode failed: %d", iface, ret);
+ eth_bridge_iface_remove(br, iface);
+ return ret;
+ }
+
+ NET_DBG("iface %p added to bridge %p", iface, br);
+ return 0;
+}
+
+int eth_bridge_iface_remove(struct eth_bridge *br, struct net_if *iface)
+{
+ struct ethernet_context *ctx = net_if_l2_data(iface);
+
+ if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
+ return -EINVAL;
+ }
+
+ k_mutex_lock(&br->lock, K_FOREVER);
+
+ if (ctx->bridge.instance != br) {
+ k_mutex_unlock(&br->lock);
+ return -EINVAL;
+ }
+
+ sys_slist_find_and_remove(&br->interfaces, &ctx->bridge.node);
+ ctx->bridge.instance = NULL;
+
+ k_mutex_unlock(&br->lock);
+
+ NET_DBG("iface %p removed from bridge %p", iface, br);
+ return 0;
+}
+
+int eth_bridge_iface_allow_tx(struct net_if *iface, bool allow)
+{
+ struct ethernet_context *ctx = net_if_l2_data(iface);
+
+ if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET) ||
+ ctx->bridge.instance == NULL) {
+ return -EINVAL;
+ }
+
+ ctx->bridge.allow_tx = allow;
+ return 0;
+}
+
+int eth_bridge_listener_add(struct eth_bridge *br, struct eth_bridge_listener *l)
+{
+ k_mutex_lock(&br->lock, K_FOREVER);
+ sys_slist_append(&br->listeners, &l->node);
+ k_mutex_unlock(&br->lock);
+ return 0;
+}
+
+int eth_bridge_listener_remove(struct eth_bridge *br, struct eth_bridge_listener *l)
+{
+ k_mutex_lock(&br->lock, K_FOREVER);
+ sys_slist_find_and_remove(&br->listeners, &l->node);
+ k_mutex_unlock(&br->lock);
+ return 0;
+}
+
+static inline bool is_link_local_addr(struct net_eth_addr *addr)
+{
+ if (addr->addr[0] == 0x01 &&
+ addr->addr[1] == 0x80 &&
+ addr->addr[2] == 0xc2 &&
+ addr->addr[3] == 0x00 &&
+ addr->addr[4] == 0x00 &&
+ (addr->addr[5] & 0x0f) == 0x00) {
+ return true;
+ }
+
+ return false;
+}
+
+enum net_verdict net_eth_bridge_input(struct ethernet_context *ctx,
+ struct net_pkt *pkt)
+{
+ struct eth_bridge *br = ctx->bridge.instance;
+ sys_snode_t *node;
+
+ NET_DBG("new pkt %p", pkt);
+
+ /* Drop all link-local packets for now. */
+ if (is_link_local_addr((struct net_eth_addr *)net_pkt_lladdr_dst(pkt))) {
+ return NET_DROP;
+ }
+
+ k_mutex_lock(&br->lock, K_FOREVER);
+
+ /*
+ * Send packet to all registered interfaces for now.
+ * Eventually we could get smarter with a MAC address cache.
+ */
+ SYS_SLIST_FOR_EACH_NODE(&br->interfaces, node) {
+ struct ethernet_context *out_ctx;
+ struct net_pkt *out_pkt;
+
+ out_ctx = CONTAINER_OF(node, struct ethernet_context, bridge.node);
+
+ /* Don't xmit on the same interface as the incoming packet's */
+ if (ctx == out_ctx) {
+ continue;
+ }
+
+ /* Skip it if not allowed to transmit */
+ if (!out_ctx->bridge.allow_tx) {
+ continue;
+ }
+
+ /* Skip it if not up */
+ if (!net_if_flag_is_set(out_ctx->iface, NET_IF_UP)) {
+ continue;
+ }
+
+ out_pkt = net_pkt_shallow_clone(pkt, K_NO_WAIT);
+ if (out_pkt == NULL) {
+ continue;
+ }
+
+ NET_DBG("sending pkt %p as %p on iface %p", pkt, out_pkt, out_ctx->iface);
+
+ /*
+ * Use AF_UNSPEC to avoid interference, set the output
+ * interface and send the packet.
+ */
+ net_pkt_set_family(out_pkt, AF_UNSPEC);
+ net_pkt_set_orig_iface(out_pkt, net_pkt_iface(pkt));
+ net_pkt_set_iface(out_pkt, out_ctx->iface);
+ net_if_queue_tx(out_ctx->iface, out_pkt);
+ }
+
+ SYS_SLIST_FOR_EACH_NODE(&br->listeners, node) {
+ struct eth_bridge_listener *l;
+ struct net_pkt *out_pkt;
+
+ l = CONTAINER_OF(node, struct eth_bridge_listener, node);
+
+ out_pkt = net_pkt_shallow_clone(pkt, K_NO_WAIT);
+ if (out_pkt == NULL) {
+ continue;
+ }
+
+ k_fifo_put(&l->pkt_queue, out_pkt);
+ }
+
+ k_mutex_unlock(&br->lock);
+
+ net_pkt_unref(pkt);
+ return NET_OK;
+}
diff --git a/subsys/net/l2/ethernet/bridge.h b/subsys/net/l2/ethernet/bridge.h
new file mode 100644
index 0000000000000..a4836fdc9d1bc
--- /dev/null
+++ b/subsys/net/l2/ethernet/bridge.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2021 BayLibre SAS
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef __BRIDGE_H
+#define __BRIDGE_H
+
+enum net_verdict net_eth_bridge_input(struct ethernet_context *ctx,
+ struct net_pkt *pkt);
+
+static inline bool net_eth_iface_is_bridged(struct ethernet_context *ctx)
+{
+#if defined(CONFIG_NET_ETHERNET_BRIDGE)
+ return ctx->bridge.instance != NULL;
+#else
+ return false;
+#endif
+}
+
+#endif /* __BRIDGE_H */
diff --git a/subsys/net/l2/ethernet/bridge_shell.c b/subsys/net/l2/ethernet/bridge_shell.c
new file mode 100644
index 0000000000000..7724973cff9a4
--- /dev/null
+++ b/subsys/net/l2/ethernet/bridge_shell.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2021 BayLibre SAS
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int get_idx(const struct shell *sh, char *index_str)
+{
+ char *endptr;
+ int idx;
+
+ idx = strtol(index_str, &endptr, 10);
+ if (*endptr != '\0') {
+ shell_warn(sh, "Invalid index %s\n", index_str);
+ return -ENOENT;
+ }
+ return idx;
+}
+
+static int cmd_bridge_addif(const struct shell *sh, size_t argc, char *argv[])
+{
+ int br_idx, if_idx;
+ struct eth_bridge *br;
+ struct net_if *iface;
+
+ br_idx = get_idx(sh, argv[1]);
+ if (br_idx < 0) {
+ return br_idx;
+ }
+ if_idx = get_idx(sh, argv[2]);
+ if (if_idx < 0) {
+ return if_idx;
+ }
+ br = eth_bridge_get_by_index(br_idx);
+ if (br == NULL) {
+ shell_warn(sh, "Bridge %d not found\n", br_idx);
+ return -ENOENT;
+ }
+ iface = net_if_get_by_index(if_idx);
+ if (iface == NULL) {
+ shell_warn(sh, "Interface %d not found\n", if_idx);
+ return -ENOENT;
+ }
+ if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
+ shell_warn(sh, "Interface %d is not Ethernet\n", if_idx);
+ return -EINVAL;
+ }
+ if (!(net_eth_get_hw_capabilities(iface) & ETHERNET_PROMISC_MODE)) {
+ shell_warn(sh, "Interface %d cannot do promiscuous mode\n", if_idx);
+ return -EINVAL;
+ }
+
+ int ret = eth_bridge_iface_add(br, iface);
+
+ if (ret < 0) {
+ shell_error(sh, "error: eth_bridge_iface_add() returned %d\n", ret);
+ }
+ return ret;
+}
+
+static int cmd_bridge_delif(const struct shell *sh, size_t argc, char *argv[])
+{
+ int br_idx, if_idx;
+ struct eth_bridge *br;
+ struct net_if *iface;
+
+ br_idx = get_idx(sh, argv[1]);
+ if (br_idx < 0) {
+ return br_idx;
+ }
+ if_idx = get_idx(sh, argv[2]);
+ if (if_idx < 0) {
+ return if_idx;
+ }
+ br = eth_bridge_get_by_index(br_idx);
+ if (br == NULL) {
+ shell_warn(sh, "Bridge %d not found\n", br_idx);
+ return -ENOENT;
+ }
+ iface = net_if_get_by_index(if_idx);
+ if (iface == NULL) {
+ shell_warn(sh, "Interface %d not found\n", if_idx);
+ return -ENOENT;
+ }
+
+ int ret = eth_bridge_iface_remove(br, iface);
+
+ if (ret < 0) {
+ shell_error(sh, "error: eth_bridge_iface_remove() returned %d\n", ret);
+ }
+ return ret;
+}
+
+static int cmd_bridge_allow_tx(const struct shell *sh, size_t argc, char *argv[])
+{
+ int br_idx, if_idx;
+ struct eth_bridge *br;
+ struct net_if *iface;
+ struct ethernet_context *ctx;
+
+ br_idx = get_idx(sh, argv[1]);
+ if (br_idx < 0) {
+ return br_idx;
+ }
+ if_idx = get_idx(sh, argv[2]);
+ if (if_idx < 0) {
+ return if_idx;
+ }
+ br = eth_bridge_get_by_index(br_idx);
+ if (br == NULL) {
+ shell_error(sh, "Bridge %d not found\n", br_idx);
+ return -ENOENT;
+ }
+ iface = net_if_get_by_index(if_idx);
+ if (iface == NULL) {
+ shell_error(sh, "Interface %d not found", if_idx);
+ return -ENOENT;
+ }
+ ctx = net_if_l2_data(iface);
+ if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET) ||
+ ctx->bridge.instance != br) {
+ shell_error(sh, "Interface %d is not tied to bridge %d",
+ if_idx, br_idx);
+ return -ENOENT;
+ }
+
+ if (!strcmp(argv[2], "1") ||
+ !strcmp(argv[2], "yes") ||
+ !strcmp(argv[2], "on") ||
+ !strcmp(argv[2], "true")) {
+ eth_bridge_iface_allow_tx(iface, true);
+ } else {
+ eth_bridge_iface_allow_tx(iface, false);
+ }
+ return 0;
+}
+
+static void bridge_show(struct eth_bridge *br, void *data)
+{
+ const struct shell *sh = data;
+ int br_idx = eth_bridge_get_index(br);
+ sys_snode_t *node;
+ bool pad;
+
+ shell_fprintf(sh, SHELL_NORMAL, "%-10d", br_idx);
+ pad = false;
+
+ k_mutex_lock(&br->lock, K_FOREVER);
+
+ SYS_SLIST_FOR_EACH_NODE(&br->interfaces, node) {
+ struct ethernet_context *ctx;
+ int if_idx;
+
+ ctx = CONTAINER_OF(node, struct ethernet_context, bridge.node);
+ if_idx = net_if_get_by_iface(ctx->iface);
+
+ if (pad) {
+ shell_fprintf(sh, SHELL_NORMAL, "%-10s", "");
+ }
+ shell_fprintf(sh, SHELL_NORMAL, "%-10d%s", if_idx,
+ ctx->bridge.allow_tx ? "*" : "");
+ pad = true;
+ }
+ shell_fprintf(sh, SHELL_NORMAL, "\n");
+
+ k_mutex_unlock(&br->lock);
+}
+
+static int cmd_bridge_show(const struct shell *sh, size_t argc, char *argv[])
+{
+ int br_idx;
+ struct eth_bridge *br = NULL;
+
+ if (argc == 2) {
+ br_idx = get_idx(sh, argv[1]);
+ if (br_idx < 0) {
+ return br_idx;
+ }
+ br = eth_bridge_get_by_index(br_idx);
+ if (br == NULL) {
+ shell_warn(sh, "Bridge %d not found\n", br_idx);
+ return -ENOENT;
+ }
+ }
+
+ shell_fprintf(sh, SHELL_NORMAL, "bridge iface tx_enabled\n");
+
+ if (br != NULL) {
+ bridge_show(br, (void *)sh);
+ } else {
+ net_eth_bridge_foreach(bridge_show, (void *)sh);
+ }
+
+ return 0;
+}
+
+SHELL_STATIC_SUBCMD_SET_CREATE(bridge_commands,
+ SHELL_CMD_ARG(addif, NULL,
+ "Add a network interface to a bridge.\n"
+ "'bridge addif '",
+ cmd_bridge_addif, 3, 0),
+ SHELL_CMD_ARG(delif, NULL,
+ "Delete a network interface from a bridge.\n"
+ "'bridge delif '",
+ cmd_bridge_delif, 3, 0),
+ SHELL_CMD_ARG(tx, NULL,
+ "Enable/disable tx from given bridged interface.\n"
+ "'bridge tx {on|off}'",
+ cmd_bridge_allow_tx, 4, 0),
+ SHELL_CMD_ARG(show, NULL,
+ "Show bridge information.\n"
+ "'bridge show []'",
+ cmd_bridge_show, 1, 1),
+ SHELL_SUBCMD_SET_END
+);
+
+SHELL_CMD_REGISTER(bridge, &bridge_commands, "Ethernet Bridge commands", NULL);
+
+#if defined(CONFIG_NET_ETHERNET_BRIDGE_DEFAULT)
+static ETH_BRIDGE_INIT(shell_default_bridge);
+#endif
diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c
index 7089d406c9b50..f656d066e73a0 100644
--- a/subsys/net/l2/ethernet/ethernet.c
+++ b/subsys/net/l2/ethernet/ethernet.c
@@ -30,6 +30,7 @@ LOG_MODULE_REGISTER(net_ethernet, CONFIG_NET_L2_ETHERNET_LOG_LEVEL);
#include "net_private.h"
#include "ipv6.h"
#include "ipv4_autoconf_internal.h"
+#include "bridge.h"
#define NET_BUF_TIMEOUT K_MSEC(100)
@@ -187,6 +188,19 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
goto drop;
}
+ if (IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE) &&
+ net_eth_iface_is_bridged(ctx)) {
+ net_pkt_set_l2_bridged(pkt, true);
+ net_pkt_lladdr_src(pkt)->addr = hdr->src.addr;
+ net_pkt_lladdr_src(pkt)->len = sizeof(struct net_eth_addr);
+ net_pkt_lladdr_src(pkt)->type = NET_LINK_ETHERNET;
+ net_pkt_lladdr_dst(pkt)->addr = hdr->dst.addr;
+ net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr);
+ net_pkt_lladdr_dst(pkt)->type = NET_LINK_ETHERNET;
+ ethernet_update_rx_stats(iface, pkt, net_pkt_get_len(pkt));
+ return net_eth_bridge_input(ctx, pkt);
+ }
+
type = ntohs(hdr->type);
if (net_eth_is_vlan_enabled(ctx, iface) &&
@@ -578,7 +592,19 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt)
goto error;
}
- if (IS_ENABLED(CONFIG_NET_IPV4) &&
+ if (IS_ENABLED(CONFIG_NET_ETHERNET_BRIDGE) &&
+ net_pkt_is_l2_bridged(pkt)) {
+ net_pkt_cursor_init(pkt);
+ ret = net_l2_send(api->send, net_if_get_device(iface), iface, pkt);
+ if (ret != 0) {
+ eth_stats_update_errors_tx(iface);
+ goto error;
+ }
+ ethernet_update_tx_stats(iface, pkt);
+ ret = net_pkt_get_len(pkt);
+ net_pkt_unref(pkt);
+ return ret;
+ } else if (IS_ENABLED(CONFIG_NET_IPV4) &&
net_pkt_family(pkt) == AF_INET) {
struct net_pkt *tmp;
diff --git a/subsys/pm/policy/CMakeLists.txt b/subsys/pm/policy/CMakeLists.txt
index 7594f7e734fb9..b7657acb1e62e 100644
--- a/subsys/pm/policy/CMakeLists.txt
+++ b/subsys/pm/policy/CMakeLists.txt
@@ -2,4 +2,3 @@
zephyr_sources_ifdef(CONFIG_PM_POLICY_DUMMY policy_dummy.c)
zephyr_sources_ifdef(CONFIG_PM_POLICY_RESIDENCY_DEFAULT policy_residency.c)
-zephyr_sources_ifdef(CONFIG_PM_POLICY_RESIDENCY_CC13X2_CC26X2 policy_residency_cc13x2_cc26x2.c)
diff --git a/subsys/pm/policy/Kconfig b/subsys/pm/policy/Kconfig
index d8bfc7271221f..80fca155a01fd 100644
--- a/subsys/pm/policy/Kconfig
+++ b/subsys/pm/policy/Kconfig
@@ -7,8 +7,7 @@ choice
config PM_POLICY_RESIDENCY
bool "PM Policy based on CPU residency"
- select PM_POLICY_RESIDENCY_DEFAULT if !SOC_SERIES_CC13X2_CC26X2
- select PM_POLICY_RESIDENCY_CC13X2_CC26X2 if SOC_SERIES_CC13X2_CC26X2
+ select PM_POLICY_RESIDENCY_DEFAULT
help
Select this option for PM policy based on CPU residencies.
@@ -28,8 +27,3 @@ config PM_POLICY_RESIDENCY_DEFAULT
bool
help
Use the default residency policy implementation
-
-config PM_POLICY_RESIDENCY_CC13X2_CC26X2
- bool
- help
- Use the residency policy implementation for TI CC13x2/CC26x2
diff --git a/subsys/pm/policy/policy_residency_cc13x2_cc26x2.c b/subsys/pm/policy/policy_residency_cc13x2_cc26x2.c
deleted file mode 100644
index f4858f31c27e5..0000000000000
--- a/subsys/pm/policy/policy_residency_cc13x2_cc26x2.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2019 Linaro Limited.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-
-#include
-#include
-#include
-
-#define LOG_LEVEL CONFIG_PM_LOG_LEVEL
-#include
-LOG_MODULE_DECLARE(power);
-
-/* Wakeup delay from standby in microseconds */
-#define WAKEDELAYSTANDBY 240
-
-#define STATE_ACTIVE \
- (struct pm_state_info){PM_STATE_ACTIVE, 0, 0}
-
-
-extern PowerCC26X2_ModuleState PowerCC26X2_module;
-
-/* PM Policy based on SoC/Platform residency requirements */
-static const struct pm_state_info residency_info[] =
- PM_STATE_INFO_DT_ITEMS_LIST(DT_NODELABEL(cpu0));
-
-struct pm_state_info pm_policy_next_state(int32_t ticks)
-{
- uint32_t constraints;
- bool disallowed = false;
- int i;
-
- /* check operating conditions, optimally choose DCDC versus GLDO */
- SysCtrl_DCDC_VoltageConditionalControl();
-
- /* query the declared constraints */
- constraints = Power_getConstraintMask();
-
- if ((ticks != K_TICKS_FOREVER) && (ticks <
- k_us_to_ticks_ceil32(residency_info[0].min_residency_us))) {
- LOG_DBG("Not enough time for PM operations: %d", ticks);
- return STATE_ACTIVE;
- }
-
- for (i = ARRAY_SIZE(residency_info) - 1; i >= 0; i--) {
- if (!pm_constraint_get(residency_info[i].state)) {
- continue;
- }
-
- if ((ticks <
- k_us_to_ticks_ceil32(residency_info[i].min_residency_us))
- && (ticks != K_TICKS_FOREVER)) {
- continue;
- }
-
- /* Verify if Power module has constraints set to
- * disallow a state
- */
- switch (residency_info[i].state) {
- case PM_STATE_SUSPEND_TO_IDLE: /* Idle mode */
- if ((constraints & (1 <<
- PowerCC26XX_DISALLOW_IDLE)) != 0) {
- disallowed = true;
- }
- break;
- case PM_STATE_STANDBY: /* Standby mode */
- if ((constraints & (1 <<
- PowerCC26XX_DISALLOW_STANDBY)) != 0) {
- disallowed = true;
- }
- /* Set timeout for wakeup event */
- __ASSERT(
- residency_info[i].min_residency_us > 1000,
- "PM_STATE_STANDBY must be greater than 1000.");
- if (ticks != K_TICKS_FOREVER) {
- /* NOTE: Ideally we'd like to set a
- * timer to wake up just a little
- * earlier to take care of the wakeup
- * sequence, ie. by WAKEDELAYSTANDBY
- * microsecs. However, given
- * k_timer_start (called later by
- * ClockP_start) does not currently
- * have sub-millisecond accuracy, wakeup
- * would be at up to (WAKEDELAYSTANDBY
- * + 1 ms) ahead of the next timeout.
- * This also has the implication that
- * PM_STATE_STANDBY
- * must be greater than 1.
- */
- ticks -= (WAKEDELAYSTANDBY *
- CONFIG_SYS_CLOCK_TICKS_PER_SEC
- + 1000000) / 1000000;
-#if (CONFIG_SYS_CLOCK_TICKS_PER_SEC <= 1000)
- /*
- * ClockP_setTimeout cannot handle any
- * more ticks
- */
- ticks = MIN(ticks, UINT32_MAX / 1000 *
- CONFIG_SYS_CLOCK_TICKS_PER_SEC);
-#endif
- ClockP_setTimeout(ClockP_handle(
- (ClockP_Struct *)
- &PowerCC26X2_module.clockObj),
- ticks);
- }
- break;
- default:
- /* This should never be reached */
- LOG_ERR("Invalid sleep state detected\n");
- }
-
- if (disallowed) {
- disallowed = false;
- continue;
- }
-
- LOG_DBG("Selected power state %d "
- "(ticks: %d, min_residency: %u)",
- residency_info[i].state, ticks,
- k_us_to_ticks_ceil32(
- residency_info[i].min_residency_us));
- return residency_info[i];
- }
-
- LOG_DBG("No suitable power state found!");
- return STATE_ACTIVE;
-}
diff --git a/tests/bluetooth/bsim_bt/bsim_test_multiple/CMakeLists.txt b/tests/bluetooth/bsim_bt/bsim_test_multiple/CMakeLists.txt
new file mode 100644
index 0000000000000..85f3344b8d32b
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_multiple/CMakeLists.txt
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.13.1)
+
+if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
+ message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set \
+ the environment variable BSIM_COMPONENTS_PATH to point to its \
+ components folder. More information can be found in \
+ https://babblesim.github.io/folder_structure_and_env.html")
+endif()
+
+find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
+project(bsim_test_multiple)
+
+target_sources(app PRIVATE
+ src/main.c
+ ${ZEPHYR_BASE}/samples/bluetooth/central_multilink/src/central_multilink.c
+ ${ZEPHYR_BASE}/samples/bluetooth/peripheral_identity/src/peripheral_identity.c
+)
+
+zephyr_include_directories(
+ $ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
+ $ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
+)
diff --git a/tests/bluetooth/bsim_bt/bsim_test_multiple/prj.conf b/tests/bluetooth/bsim_bt/bsim_test_multiple/prj.conf
new file mode 100644
index 0000000000000..2baba549f15c1
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_multiple/prj.conf
@@ -0,0 +1,16 @@
+CONFIG_BT=y
+CONFIG_BT_PERIPHERAL=y
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_AUTO_PHY_UPDATE=n
+CONFIG_BT_PRIVACY=y
+
+CONFIG_BT_DEVICE_NAME="Multiple"
+CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
+
+CONFIG_BT_MAX_CONN=62
+CONFIG_BT_ID_MAX=62
+
+# CONFIG_BT_GATT_CLIENT=y
+
+# CONFIG_BT_SMP=y
+# CONFIG_BT_MAX_PAIRED=62
diff --git a/tests/bluetooth/bsim_bt/bsim_test_multiple/src/main.c b/tests/bluetooth/bsim_bt/bsim_test_multiple/src/main.c
new file mode 100644
index 0000000000000..20b42b494073e
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_multiple/src/main.c
@@ -0,0 +1,116 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+
+#include
+#include
+
+#include "bs_types.h"
+#include "bs_tracing.h"
+#include "time_machine.h"
+#include "bstests.h"
+
+int init_central(void);
+int init_peripheral(void);
+
+#define FAIL(...) \
+ do { \
+ bst_result = Failed; \
+ bs_trace_error_time_line(__VA_ARGS__); \
+ } while (0)
+
+#define PASS(...) \
+ do { \
+ bst_result = Passed; \
+ bs_trace_info_time(1, __VA_ARGS__); \
+ } while (0)
+
+extern enum bst_result_t bst_result;
+
+static void test_central_main(void)
+{
+ int err;
+
+ err = init_central();
+ if (err) {
+ goto exit;
+ }
+
+ PASS("Central tests passed\n");
+ bs_trace_silent_exit(0);
+
+ return;
+
+exit:
+ FAIL("Central tests failed (%d)\n", err);
+ bs_trace_silent_exit(0);
+}
+
+static void test_peripheral_main(void)
+{
+ int err;
+
+ err = init_peripheral();
+ if (err) {
+ goto exit;
+ }
+
+ PASS("Peripheral tests passed\n");
+
+ return;
+
+exit:
+ FAIL("Peripheral tests failed (%d)\n", err);
+ bs_trace_silent_exit(0);
+}
+
+static void test_multiple_init(void)
+{
+ bst_ticker_set_next_tick_absolute(20e6);
+ bst_result = In_progress;
+}
+
+static void test_multiple_tick(bs_time_t HW_device_time)
+{
+ bst_result = Failed;
+ bs_trace_error_line("Test multiple finished.\n");
+}
+
+static const struct bst_test_instance test_def[] = {
+ {
+ .test_id = "central",
+ .test_descr = "Central Multilink",
+ .test_post_init_f = test_multiple_init,
+ .test_tick_f = test_multiple_tick,
+ .test_main_f = test_central_main
+ },
+ {
+ .test_id = "peripheral",
+ .test_descr = "Peripheral multiple identity",
+ .test_post_init_f = test_multiple_init,
+ .test_tick_f = test_multiple_tick,
+ .test_main_f = test_peripheral_main
+ },
+ BSTEST_END_MARKER
+};
+
+struct bst_test_list *test_multiple_install(struct bst_test_list *tests)
+{
+ return bst_add_tests(tests, test_def);
+}
+
+bst_test_install_t test_installers[] = {
+ test_multiple_install,
+ NULL
+};
+
+void main(void)
+{
+ bst_main();
+}
diff --git a/tests/bluetooth/bsim_bt/bsim_test_multiple/tests_scripts/multiple.sh b/tests/bluetooth/bsim_bt/bsim_test_multiple/tests_scripts/multiple.sh
new file mode 100755
index 0000000000000..0cea1fe022e88
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_multiple/tests_scripts/multiple.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# Copyright 2018 Oticon A/S
+# SPDX-License-Identifier: Apache-2.0
+
+# Multiple connection between two devices with multiple peripheral identity
+simulation_id="multiple"
+verbosity_level=2
+process_ids=""; exit_code=0
+
+function Execute(){
+ if [ ! -f $1 ]; then
+ echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
+ compile it?)\e[39m"
+ exit 1
+ fi
+ timeout 30 $@ & process_ids="$process_ids $!"
+}
+
+: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
+
+#Give a default value to BOARD if it does not have one yet:
+BOARD="${BOARD:-nrf52_bsim}"
+
+cd ${BSIM_OUT_PATH}/bin
+
+Execute ./bs_${BOARD}_tests_bluetooth_bsim_bt_bsim_test_multiple_prj_conf \
+ -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central
+
+Execute ./bs_${BOARD}_tests_bluetooth_bsim_bt_bsim_test_multiple_prj_conf\
+ -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral
+
+Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
+ -D=2 -sim_length=60e6 $@
+
+for process_id in $process_ids; do
+ wait $process_id || let "exit_code=$?"
+done
+exit $exit_code #the last exit code != 0
diff --git a/tests/bluetooth/bsim_bt/compile.sh b/tests/bluetooth/bsim_bt/compile.sh
index 5a5a11fad0cbe..b559e3bc8efa6 100755
--- a/tests/bluetooth/bsim_bt/compile.sh
+++ b/tests/bluetooth/bsim_bt/compile.sh
@@ -57,6 +57,7 @@ app=tests/bluetooth/bsim_bt/bsim_test_app conf_file=prj_split_privacy.conf \
compile
app=tests/bluetooth/bsim_bt/bsim_test_app conf_file=prj_split_low_lat.conf \
compile
+app=tests/bluetooth/bsim_bt/bsim_test_multiple compile
app=tests/bluetooth/bsim_bt/bsim_test_advx compile
app=tests/bluetooth/bsim_bt/bsim_test_iso compile
app=tests/bluetooth/bsim_bt/bsim_test_audio compile
diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml
index 90f310d99e822..3fb3f9f9bbed7 100644
--- a/tests/bluetooth/shell/testcase.yaml
+++ b/tests/bluetooth/shell/testcase.yaml
@@ -32,6 +32,7 @@ tests:
# Bluetooth Audio Compile validation tests
bluetooth.shell.no_vcs:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -39,6 +40,7 @@ tests:
tags: bluetooth
bluetooth.shell.no_vocs:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -47,6 +49,7 @@ tests:
tags: bluetooth
bluetooth.shell.no_aics:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -56,6 +59,7 @@ tests:
tags: bluetooth
bluetooth.shell.no_aics_vocs:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -67,6 +71,7 @@ tests:
tags: bluetooth
bluetooth.shell.no_vcs_client:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -74,6 +79,7 @@ tests:
tags: bluetooth
bluetooth.shell.no_vcs_vcs_client:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -82,6 +88,7 @@ tests:
tags: bluetooth
bluetooth.shell.vcs_client_no_aics_client:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -89,6 +96,7 @@ tests:
tags: bluetooth
bluetooth.shell.vcs_client_no_vocs_client:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -96,6 +104,7 @@ tests:
tags: bluetooth
bluetooth.shell.no_mics:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
@@ -103,12 +112,14 @@ tests:
tags: bluetooth
bluetooth.shell.no_mics_client:
build_only: true
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
integration_platforms:
- native_posix
extra_configs:
- CONFIG_BT_MICS_CLIENT=n
tags: bluetooth
bluetooth.shell.no_mics_mics_client:
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
build_only: true
integration_platforms:
- native_posix
@@ -117,6 +128,7 @@ tests:
- CONFIG_BT_MICS_CLIENT=n
tags: bluetooth
bluetooth.shell.mics_client_no_aics_client:
+ filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
build_only: true
integration_platforms:
- native_posix
diff --git a/tests/drivers/dac/dac_loopback/boards/nucleo_f429zi.overlay b/tests/drivers/dac/dac_loopback/boards/nucleo_f429zi.overlay
new file mode 100644
index 0000000000000..c0ef8350ed63d
--- /dev/null
+++ b/tests/drivers/dac/dac_loopback/boards/nucleo_f429zi.overlay
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2021 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+&dac1 {
+ status = "okay";
+ pinctrl-0 = <&dac_out1_pa4>;
+};
diff --git a/tests/drivers/dac/dac_loopback/src/test_dac.c b/tests/drivers/dac/dac_loopback/src/test_dac.c
index 8926dd278b2e9..80e741b007f44 100644
--- a/tests/drivers/dac/dac_loopback/src/test_dac.c
+++ b/tests/drivers/dac/dac_loopback/src/test_dac.c
@@ -49,7 +49,9 @@
#define ADC_REFERENCE ADC_REF_INTERNAL
#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
-#elif defined(CONFIG_BOARD_NUCLEO_F207ZG)
+#elif defined(CONFIG_BOARD_NUCLEO_F207ZG) || \
+ defined(CONFIG_BOARD_NUCLEO_F429ZI) || \
+ defined(CONFIG_BOARD_NUCLEO_F746ZG)
/*
* DAC output on PA4
* ADC input read from PA0
diff --git a/tests/drivers/dac/dac_loopback/testcase.yaml b/tests/drivers/dac/dac_loopback/testcase.yaml
index 41e9c7413a88a..a68b09f50e298 100644
--- a/tests/drivers/dac/dac_loopback/testcase.yaml
+++ b/tests/drivers/dac/dac_loopback/testcase.yaml
@@ -9,4 +9,4 @@ tests:
platform_allow: |
frdm_k22f frdm_k64f nucleo_f207zg nucleo_l073rz nucleo_l152re twr_ke18f
bl652_dvk bl653_dvk bl654_dvk bl5340_dvk_cpuapp stm32f3_disco stm32l562e_dk
- nucleo_l552ze_q
+ nucleo_l552ze_q nucleo_f429zi nucleo_f746zg
diff --git a/tests/drivers/gpio/gpio_basic_api/boards/tlsr9518adk80d.overlay b/tests/drivers/gpio/gpio_basic_api/boards/tlsr9518adk80d.overlay
new file mode 100644
index 0000000000000..8a9b8f2394705
--- /dev/null
+++ b/tests/drivers/gpio/gpio_basic_api/boards/tlsr9518adk80d.overlay
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2021 Telink Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/ {
+ resources {
+ compatible = "test,gpio_basic_api";
+ out-gpios = <&gpioc 6 0>; /* Port C 6 */
+ in-gpios = <&gpioc 7 0>; /* Port C 7 */
+ };
+};
diff --git a/tests/net/bridge/CMakeLists.txt b/tests/net/bridge/CMakeLists.txt
new file mode 100644
index 0000000000000..07f1c56f52516
--- /dev/null
+++ b/tests/net/bridge/CMakeLists.txt
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.13.1)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(bridge)
+
+target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip)
+FILE(GLOB app_sources src/*.c)
+target_sources(app PRIVATE ${app_sources})
diff --git a/tests/net/bridge/prj.conf b/tests/net/bridge/prj.conf
new file mode 100644
index 0000000000000..8a568ddd56de8
--- /dev/null
+++ b/tests/net/bridge/prj.conf
@@ -0,0 +1,12 @@
+CONFIG_NETWORKING=y
+CONFIG_NET_TEST=y
+CONFIG_NET_L2_ETHERNET=y
+CONFIG_NET_ETHERNET_BRIDGE=y
+CONFIG_NET_LOG=y
+CONFIG_ENTROPY_GENERATOR=y
+CONFIG_TEST_RANDOM_GENERATOR=y
+CONFIG_NET_PKT_TX_COUNT=10
+CONFIG_NET_PKT_RX_COUNT=10
+CONFIG_NET_BUF_RX_COUNT=10
+CONFIG_NET_BUF_TX_COUNT=10
+CONFIG_ZTEST=y
diff --git a/tests/net/bridge/src/main.c b/tests/net/bridge/src/main.c
new file mode 100644
index 0000000000000..11aec9d546d6d
--- /dev/null
+++ b/tests/net/bridge/src/main.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2021 BayLibre SAS
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define NET_LOG_LEVEL CONFIG_NET_ETHERNET_BRIDGE_LOG_LEVEL
+
+#include
+LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL);
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
+#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
+#else
+#define DBG(fmt, ...)
+#endif
+
+struct eth_fake_context {
+ struct net_if *iface;
+ struct net_pkt *sent_pkt;
+ uint8_t mac_address[6];
+ bool promisc_mode;
+};
+
+static void eth_fake_iface_init(struct net_if *iface)
+{
+ const struct device *dev = net_if_get_device(iface);
+ struct eth_fake_context *ctx = dev->data;
+
+ ctx->iface = iface;
+
+ ctx->mac_address[0] = 0xc2;
+ ctx->mac_address[1] = 0xaa;
+ ctx->mac_address[2] = 0xbb;
+ ctx->mac_address[3] = 0xcc;
+ ctx->mac_address[4] = 0xdd;
+ ctx->mac_address[5] = 0xee;
+
+ net_if_set_link_addr(iface, ctx->mac_address,
+ sizeof(ctx->mac_address),
+ NET_LINK_ETHERNET);
+
+ ethernet_init(iface);
+}
+
+static int eth_fake_send(const struct device *dev,
+ struct net_pkt *pkt)
+{
+ struct eth_fake_context *ctx = dev->data;
+ struct net_eth_hdr *eth_hdr = NET_ETH_HDR(pkt);
+
+ /*
+ * Ignore packets we don't care about for this test, like
+ * the IP autoconfig related ones, etc.
+ */
+ if (eth_hdr->type != htons(NET_ETH_PTYPE_ALL)) {
+ DBG("Fake send ignoring pkt %p\n", pkt);
+ return 0;
+ }
+
+ if (ctx->sent_pkt != NULL) {
+ DBG("Fake send found pkt %p while sending %p\n",
+ ctx->sent_pkt, pkt);
+ return -EBUSY;
+ }
+ ctx->sent_pkt = net_pkt_shallow_clone(pkt, K_NO_WAIT);
+ if (ctx->sent_pkt == NULL) {
+ DBG("Fake send out of mem while sending pkt %p\n", pkt);
+ return -ENOMEM;
+ }
+
+ DBG("Fake send pkt %p kept locally as %p\n", pkt, ctx->sent_pkt);
+ return 0;
+}
+
+static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev)
+{
+ return ETHERNET_PROMISC_MODE;
+}
+
+static int eth_fake_set_config(const struct device *dev,
+ enum ethernet_config_type type,
+ const struct ethernet_config *config)
+{
+ struct eth_fake_context *ctx = dev->data;
+
+ switch (type) {
+ case ETHERNET_CONFIG_TYPE_PROMISC_MODE:
+ if (config->promisc_mode == ctx->promisc_mode) {
+ return -EALREADY;
+ }
+
+ ctx->promisc_mode = config->promisc_mode;
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct ethernet_api eth_fake_api_funcs = {
+ .iface_api.init = eth_fake_iface_init,
+ .get_capabilities = eth_fake_get_capabilities,
+ .set_config = eth_fake_set_config,
+ .send = eth_fake_send,
+};
+
+static int eth_fake_init(const struct device *dev)
+{
+ struct eth_fake_context *ctx = dev->data;
+
+ ctx->promisc_mode = false;
+
+ return 0;
+}
+
+static struct eth_fake_context eth_fake_data[3];
+
+ETH_NET_DEVICE_INIT(eth_fake0, "eth_fake0",
+ eth_fake_init, NULL,
+ ð_fake_data[0], NULL, CONFIG_ETH_INIT_PRIORITY,
+ ð_fake_api_funcs, NET_ETH_MTU);
+
+ETH_NET_DEVICE_INIT(eth_fake1, "eth_fake1",
+ eth_fake_init, NULL,
+ ð_fake_data[1], NULL, CONFIG_ETH_INIT_PRIORITY,
+ ð_fake_api_funcs, NET_ETH_MTU);
+
+ETH_NET_DEVICE_INIT(eth_fake2, "eth_fake2",
+ eth_fake_init, NULL,
+ ð_fake_data[2], NULL, CONFIG_ETH_INIT_PRIORITY,
+ ð_fake_api_funcs, NET_ETH_MTU);
+
+static struct net_if *fake_iface[3];
+
+static void iface_cb(struct net_if *iface, void *user_data)
+{
+ static int if_count;
+
+ if (if_count >= ARRAY_SIZE(fake_iface)) {
+ return;
+ }
+
+ DBG("Interface %p [%d]\n", iface, net_if_get_by_iface(iface));
+
+ if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
+ const struct ethernet_api *api =
+ net_if_get_device(iface)->api;
+
+ /*
+ * We want to only use struct net_if devices defined in
+ * this test as board on which it is run can have its
+ * own set of interfaces.
+ */
+ if (api->get_capabilities ==
+ eth_fake_api_funcs.get_capabilities) {
+ fake_iface[if_count++] = iface;
+ }
+ }
+}
+
+static int orig_rx_num_blocks;
+static int orig_tx_num_blocks;
+
+static void get_free_packet_count(void)
+{
+ struct k_mem_slab *rx, *tx;
+
+ net_pkt_get_info(&rx, &tx, NULL, NULL);
+ orig_rx_num_blocks = rx->num_blocks;
+ orig_tx_num_blocks = tx->num_blocks;
+}
+
+static void check_free_packet_count(void)
+{
+ struct k_mem_slab *rx, *tx;
+
+ net_pkt_get_info(&rx, &tx, NULL, NULL);
+ zassert_equal(rx->num_blocks, orig_rx_num_blocks, "");
+ zassert_equal(tx->num_blocks, orig_tx_num_blocks, "");
+}
+
+static void test_iface_setup(void)
+{
+ net_if_foreach(iface_cb, NULL);
+
+ zassert_not_null(fake_iface[0], "");
+ zassert_not_null(fake_iface[1], "");
+ zassert_not_null(fake_iface[2], "");
+
+ DBG("Interfaces: [%d] iface0 %p, [%d] iface1 %p, [%d] iface2 %p\n",
+ net_if_get_by_iface(fake_iface[0]), fake_iface[0],
+ net_if_get_by_iface(fake_iface[1]), fake_iface[1],
+ net_if_get_by_iface(fake_iface[2]), fake_iface[2]);
+
+ net_if_up(fake_iface[0]);
+ net_if_up(fake_iface[1]);
+ net_if_up(fake_iface[2]);
+
+ /* Remember the initial number of free packets in the pool. */
+ get_free_packet_count();
+}
+
+/*
+ * Simulate a packet reception from the outside world
+ */
+static void _recv_data(struct net_if *iface)
+{
+ struct net_pkt *pkt;
+ struct net_eth_hdr eth_hdr;
+ static uint8_t data[] = { 't', 'e', 's', 't', '\0' };
+ int ret;
+
+ pkt = net_pkt_rx_alloc_with_buffer(iface, sizeof(eth_hdr) + sizeof(data),
+ AF_UNSPEC, 0, K_FOREVER);
+ zassert_not_null(pkt, "");
+
+ /*
+ * The source and destination MAC addresses are completely arbitrary
+ * except for the U/L and I/G bits. However, the index of the faked
+ * incoming interface is mixed in as well to create some variation,
+ * and to help with validation on the transmit side.
+ */
+
+ eth_hdr.dst.addr[0] = 0xb2;
+ eth_hdr.dst.addr[1] = 0x11;
+ eth_hdr.dst.addr[2] = 0x22;
+ eth_hdr.dst.addr[3] = 0x33;
+ eth_hdr.dst.addr[4] = net_if_get_by_iface(iface);
+ eth_hdr.dst.addr[5] = 0x55;
+
+ eth_hdr.src.addr[0] = 0xa2;
+ eth_hdr.src.addr[1] = 0x11;
+ eth_hdr.src.addr[2] = 0x22;
+ eth_hdr.src.addr[3] = net_if_get_by_iface(iface);
+ eth_hdr.src.addr[4] = 0x77;
+ eth_hdr.src.addr[5] = 0x88;
+
+ eth_hdr.type = htons(NET_ETH_PTYPE_ALL);
+
+ ret = net_pkt_write(pkt, ð_hdr, sizeof(eth_hdr));
+ zassert_equal(ret, 0, "");
+
+ ret = net_pkt_write(pkt, data, sizeof(data));
+ zassert_equal(ret, 0, "");
+
+ DBG("Fake recv pkt %p\n", pkt);
+ ret = net_recv_data(iface, pkt);
+ zassert_equal(ret, 0, "");
+}
+
+static void test_recv_before_bridging(void)
+{
+ /* fake some packet reception */
+ _recv_data(fake_iface[0]);
+ _recv_data(fake_iface[1]);
+ _recv_data(fake_iface[2]);
+
+ /* give time to the processing threads to run */
+ k_sleep(K_MSEC(100));
+
+ /* nothing should have been transmitted at this point */
+ zassert_is_null(eth_fake_data[0].sent_pkt, "");
+ zassert_is_null(eth_fake_data[1].sent_pkt, "");
+ zassert_is_null(eth_fake_data[2].sent_pkt, "");
+
+ /* and everything already dropped. */
+ check_free_packet_count();
+}
+
+static ETH_BRIDGE_INIT(test_bridge);
+
+static void test_setup_bridge(void)
+{
+ int ret;
+
+ /* add our interfaces to the bridge */
+ ret = eth_bridge_iface_add(&test_bridge, fake_iface[0]);
+ zassert_equal(ret, 0, "");
+ ret = eth_bridge_iface_add(&test_bridge, fake_iface[1]);
+ zassert_equal(ret, 0, "");
+ ret = eth_bridge_iface_add(&test_bridge, fake_iface[2]);
+ zassert_equal(ret, 0, "");
+
+ /* enable tx for them except fake_iface[1] */
+ ret = eth_bridge_iface_allow_tx(fake_iface[0], true);
+ zassert_equal(ret, 0, "");
+ ret = eth_bridge_iface_allow_tx(fake_iface[2], true);
+ zassert_equal(ret, 0, "");
+}
+
+static void test_recv_with_bridge(void)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++) {
+ int src_if_idx = net_if_get_by_iface(fake_iface[i]);
+
+ /* fake reception of packets */
+ _recv_data(fake_iface[i]);
+
+ /* give time to the processing threads to run */
+ k_sleep(K_MSEC(100));
+
+ /* nothing should have been transmitted on fake_iface[1] */
+ zassert_is_null(eth_fake_data[1].sent_pkt, "");
+
+ /*
+ * fake_iface[0] and fake_iface[2] should have sent the packet
+ * but only if it didn't come from them.
+ * We skip fake_iface[1] handled above.
+ */
+ for (j = 0; j < 3; j += 2) {
+ struct net_pkt *pkt = eth_fake_data[j].sent_pkt;
+
+ if (eth_fake_data[j].iface == fake_iface[i]) {
+ zassert_is_null(pkt, "");
+ continue;
+ }
+
+ eth_fake_data[j].sent_pkt = NULL;
+ zassert_not_null(pkt, "");
+
+ /* make sure nothing messed up our ethernet header */
+ struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
+
+ zassert_equal(hdr->dst.addr[0], 0xb2, "");
+ zassert_equal(hdr->src.addr[0], 0xa2, "");
+ zassert_equal(hdr->dst.addr[4], src_if_idx, "");
+ zassert_equal(hdr->src.addr[3], src_if_idx, "");
+
+ net_pkt_unref(pkt);
+ }
+ }
+
+ check_free_packet_count();
+}
+
+static void test_recv_after_bridging(void)
+{
+ int ret;
+
+ /* remove our interfaces from the bridge */
+ ret = eth_bridge_iface_remove(&test_bridge, fake_iface[0]);
+ zassert_equal(ret, 0, "");
+ ret = eth_bridge_iface_remove(&test_bridge, fake_iface[1]);
+ zassert_equal(ret, 0, "");
+ ret = eth_bridge_iface_remove(&test_bridge, fake_iface[2]);
+ zassert_equal(ret, 0, "");
+
+ /* things should have returned to the pre-bridging state */
+ test_recv_before_bridging();
+}
+
+void test_main(void)
+{
+ ztest_test_suite(net_eth_bridge_test,
+ ztest_unit_test(test_iface_setup),
+ ztest_unit_test(test_recv_before_bridging),
+ ztest_unit_test(test_setup_bridge),
+ ztest_unit_test(test_recv_with_bridge),
+ ztest_unit_test(test_recv_after_bridging));
+
+ ztest_run_test_suite(net_eth_bridge_test);
+}
diff --git a/tests/net/bridge/testcase.yaml b/tests/net/bridge/testcase.yaml
new file mode 100644
index 0000000000000..178e5020d09c1
--- /dev/null
+++ b/tests/net/bridge/testcase.yaml
@@ -0,0 +1,13 @@
+common:
+ min_ram: 16
+ tags: net bridge
+ depends_on: netif
+tests:
+ net.eth_bridge:
+ extra_configs:
+ - CONFIG_NET_IPV4=n
+ - CONFIG_NET_IPV6=n
+ net.eth_bridge.ip:
+ extra_configs:
+ - CONFIG_NET_IPV4=y
+ - CONFIG_NET_IPV6=y
diff --git a/west.yml b/west.yml
index 2deafbf32aeb7..5b5146de36ef7 100644
--- a/west.yml
+++ b/west.yml
@@ -34,69 +34,118 @@ manifest:
- name: cmsis
revision: c3bd2094f92d574377f7af2aec147ae181aa5f8e
path: modules/hal/cmsis
+ groups:
+ - hal
- name: edtt
revision: 7dd56fc100d79cc45c33d43e7401d1803e26f6e7
path: tools/edtt
+ groups:
+ - tools
- name: fatfs
revision: 1d1fcc725aa1cb3c32f366e0c53d7490d0fe1109
path: modules/fs/fatfs
+ groups:
+ - fs
- name: hal_altera
revision: 23c1c1dd7a0c1cc9a399509d1819375847c95b97
path: modules/hal/altera
+ groups:
+ - hal
- name: hal_atmel
revision: d17b7dd92d209b20bc1e15431d068edc29bf438d
path: modules/hal/atmel
+ groups:
+ - hal
- name: hal_cypress
revision: 81a059f21435bc7e315bccd720da5a9b615bbb50
path: modules/hal/cypress
+ groups:
+ - hal
- name: hal_espressif
revision: f525ee6f468c2c68119731e1453ad72d189a1277
path: modules/hal/espressif
+ groups:
+ - hal
west-commands: west/west-commands.yml
revision: c21d252a2188fcb60d52dceb6b018a9f4a371817
path: modules/hal/espressif
+ groups:
+ - hal
- name: hal_infineon
revision: f1fa8241f8786198ba41155413243de36ed878a5
path: modules/hal/infineon
+ groups:
+ - hal
- name: hal_microchip
revision: b280eec5d3b1296b231117c1999bcd0269b6ecc4
path: modules/hal/microchip
+ groups:
+ - hal
- name: hal_nordic
revision: d979c8dc313e4dc3e52d5606c28622e5278be50c
path: modules/hal/nordic
+ groups:
+ - hal
- name: hal_nuvoton
revision: b4d31f33238713a568e23618845702fadd67386f
path: modules/hal/nuvoton
+ groups:
+ - hal
- name: hal_nxp
revision: 4b493d4346e841e786a8daa2eb2ee03cbe5cfd37
path: modules/hal/nxp
+ groups:
+ - hal
- name: hal_openisa
revision: 40d049f69c50b58ea20473bee14cf93f518bf262
path: modules/hal/openisa
+ groups:
+ - hal
- name: hal_quicklogic
revision: b3a66fe6d04d87fd1533a5c8de51d0599fcd08d0
path: modules/hal/quicklogic
repo-path: hal_quicklogic
+ groups:
+ - hal
- name: hal_silabs
revision: be39d4eebeddac6e18e9c0c3ba1b31ad1e82eaed
path: modules/hal/silabs
+ groups:
+ - hal
- name: hal_st
revision: 575de9d461aa6f430cf62c58a053675377e700f3
path: modules/hal/st
+ groups:
+ - hal
- name: hal_stm32
revision: 2016f613f8138b8abe42013ab983a0d2fe0459b9
path: modules/hal/stm32
+ groups:
+ - hal
+ - name: hal_telink
+ revision: ffcfd6282aa213f1dc0848dbca6279b098f6b143
+ path: modules/hal/telink
+ groups:
+ - hal
- name: hal_ti
revision: 3da6fae25fc44ec830fac4a92787b585ff55435e
path: modules/hal/ti
+ groups:
+ - hal
- name: hal_xtensa
revision: 2f04b615cd5ad3a1b8abef33f9bdd10cc1990ed6
path: modules/hal/xtensa
+ groups:
+ - hal
- name: libmetal
revision: 39d049d4ae68e6f6d595fce7de1dcfc1024fb4eb
path: modules/hal/libmetal
+ groups:
+ - hal
- name: littlefs
path: modules/fs/littlefs
+ groups:
+ - fs
revision: 9e4498d1c73009acd84bb36036ee5e2869112a6c
- name: loramac-node
revision: 12019623bbad9eb54fe51066847a7cbd4b4eac57
@@ -110,6 +159,8 @@ manifest:
- name: mbedtls
revision: 5765cb7f75a9973ae9232d438e361a9d7bbc49e7
path: modules/crypto/mbedtls
+ groups:
+ - crypto
- name: mcuboot
revision: 7a5196820ba48a6ad7e7d573c9048c021960677c
path: bootloader/mcuboot
@@ -118,6 +169,8 @@ manifest:
path: modules/lib/mcumgr
- name: mipi-sys-t
path: modules/debug/mipi-sys-t
+ groups:
+ - debug
revision: 75e671550ac1acb502f315fe4952514dc73f7bfb
- name: nanopb
revision: d148bd26718e4c10414f07a7eb1bd24c62e56c5d
@@ -125,6 +178,8 @@ manifest:
- name: net-tools
revision: f49bd1354616fae4093bf36e5eaee43c51a55127
path: tools/net-tools
+ groups:
+ - tools
- name: nrf_hw_models
revision: a47e326ca772ddd14cc3b9d4ca30a9ab44ecca16
path: modules/bsim_hw_models/nrf_hw_models
@@ -137,6 +192,8 @@ manifest:
- name: segger
revision: 3a52ab222133193802d3c3b4d21730b9b1f1d2f6
path: modules/debug/segger
+ groups:
+ - debug
- name: sof
revision: 779f28ed465c03899c8a7d4aaf399856f4e51158
path: modules/audio/sof
@@ -147,6 +204,8 @@ manifest:
- name: tfm-mcuboot # This is used by the trusted-firmware-m module.
revision: v1.7.2
path: modules/tee/tfm-mcuboot
+ groups:
+ - tee
repo-path: mcuboot
- name: tinycbor
revision: 40daca97b478989884bffb5226e9ab73ca54b8c4
@@ -154,12 +213,18 @@ manifest:
- name: tinycrypt
revision: 3e9a49d2672ec01435ffbf0d788db6d95ef28de0
path: modules/crypto/tinycrypt
+ groups:
+ - crypto
- name: TraceRecorderSource
revision: 5b5f8d7adbf0e93a09087e8f5708f0eebb8b25bf
path: modules/debug/TraceRecorder
+ groups:
+ - debug
- name: trusted-firmware-m
path: modules/tee/tfm
revision: e18b7a9b040b5b5324520388047c9e7d678447e6
+ groups:
+ - tee
self:
path: zephyr