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