From e8fc9f5de95b78e8b08d81c6aee87f92f2b85d9c Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Mon, 29 Nov 2021 23:10:37 +0200 Subject: [PATCH 1/8] west.yml: Added hal_rpi_pico Added HAL module for the Raspberry Pi Pico. Signed-off-by: Yonatan Schachter --- west.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/west.yml b/west.yml index 1ad354b3dab6e..23d105a602083 100644 --- a/west.yml +++ b/west.yml @@ -113,6 +113,11 @@ manifest: repo-path: hal_quicklogic groups: - hal + - name: hal_rpi_pico + path: modules/hal/rpi_pico + revision: pull/1/head + groups: + - hal - name: hal_silabs revision: be39d4eebeddac6e18e9c0c3ba1b31ad1e82eaed path: modules/hal/silabs From dcfc6d0566db3f0285372ba402a2408b714dd139 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Mon, 29 Nov 2021 23:51:48 +0200 Subject: [PATCH 2/8] soc: Added support for Raspberry Pi's RP2040 SoC Added basic support for the RP2040 SoC. Support includes booting and starting the kernel, on one core only. Signed-off-by: Yonatan Schachter Signed-off-by: Ioannis Glaropoulos --- CODEOWNERS | 2 + dts/arm/rpi_pico/rp2040.dtsi | 51 +++++++++++ dts/arm/rpi_pico/rpi_pico_common.dtsi | 9 ++ modules/hal_rpi_pico/CMakeLists.txt | 91 +++++++++++++++++++ modules/hal_rpi_pico/Kconfig | 15 +++ modules/hal_rpi_pico/pico/config_autogen.h | 44 +++++++++ modules/hal_rpi_pico/pico/version.h | 7 ++ soc/arm/rpi_pico/CMakeLists.txt | 3 + soc/arm/rpi_pico/Kconfig | 18 ++++ soc/arm/rpi_pico/Kconfig.defconfig | 10 ++ soc/arm/rpi_pico/Kconfig.soc | 6 ++ soc/arm/rpi_pico/rp2/CMakeLists.txt | 9 ++ soc/arm/rpi_pico/rp2/Kconfig.defconfig.rp2040 | 8 ++ soc/arm/rpi_pico/rp2/Kconfig.defconfig.series | 17 ++++ soc/arm/rpi_pico/rp2/Kconfig.series | 18 ++++ soc/arm/rpi_pico/rp2/Kconfig.soc | 28 ++++++ soc/arm/rpi_pico/rp2/linker.ld | 22 +++++ soc/arm/rpi_pico/rp2/rp2_init.c | 36 ++++++++ soc/arm/rpi_pico/rp2/soc.c | 52 +++++++++++ soc/arm/rpi_pico/rp2/soc.h | 18 ++++ 20 files changed, 464 insertions(+) create mode 100644 dts/arm/rpi_pico/rp2040.dtsi create mode 100644 dts/arm/rpi_pico/rpi_pico_common.dtsi create mode 100644 modules/hal_rpi_pico/CMakeLists.txt create mode 100644 modules/hal_rpi_pico/Kconfig create mode 100644 modules/hal_rpi_pico/pico/config_autogen.h create mode 100644 modules/hal_rpi_pico/pico/version.h create mode 100644 soc/arm/rpi_pico/CMakeLists.txt create mode 100644 soc/arm/rpi_pico/Kconfig create mode 100644 soc/arm/rpi_pico/Kconfig.defconfig create mode 100644 soc/arm/rpi_pico/Kconfig.soc create mode 100644 soc/arm/rpi_pico/rp2/CMakeLists.txt create mode 100644 soc/arm/rpi_pico/rp2/Kconfig.defconfig.rp2040 create mode 100644 soc/arm/rpi_pico/rp2/Kconfig.defconfig.series create mode 100644 soc/arm/rpi_pico/rp2/Kconfig.series create mode 100644 soc/arm/rpi_pico/rp2/Kconfig.soc create mode 100644 soc/arm/rpi_pico/rp2/linker.ld create mode 100644 soc/arm/rpi_pico/rp2/rp2_init.c create mode 100644 soc/arm/rpi_pico/rp2/soc.c create mode 100644 soc/arm/rpi_pico/rp2/soc.h diff --git a/CODEOWNERS b/CODEOWNERS index 9225e294f1951..99bd78ebeb0aa 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -45,6 +45,7 @@ /soc/arm/nuvoton_npcx/ @MulinChao @WealianLiao @ChiHuaL /soc/arm/nuvoton_numicro/ @ssekar15 /soc/arm/quicklogic_eos_s3/ @kowalewskijan @kgugala +/soc/arm/rpi_pico/ @yonsch /soc/arm/silabs_exx32/efm32pg1b/ @rdmeneze /soc/arm/silabs_exx32/efr32mg21/ @l-alfred /soc/arm/st_stm32/ @erwango @@ -443,6 +444,7 @@ /dts/arm/nuvoton/ @ssekar15 @MulinChao @WealianLiao @ChiHuaL /dts/arm/nxp/ @mmahadevan108 @dleach02 /dts/arm/microchip/ @franciscomunoz @albertofloyd @sjvasanth1 +/dts/arm/rpi_pico/ @yonsch /dts/arm/silabs/efm32_pg_1b.dtsi @rdmeneze /dts/arm/silabs/efm32gg11b* @oanerer /dts/arm/silabs/efm32_jg_pg* @chrta diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi new file mode 100644 index 0000000000000..b0714f02157c8 --- /dev/null +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "rpi_pico_common.dtsi" + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m0+"; + reg = <0>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-m0+"; + reg = <1>; + }; + }; + + soc { + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(264)>; + }; + + flash0: flash@10000000 { + compatible = "soc-nv-flash"; + label = "FLASH_RP2"; + + write-block-size = <1>; + }; + + peripheral_clk: peripheral-clk { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; diff --git a/dts/arm/rpi_pico/rpi_pico_common.dtsi b/dts/arm/rpi_pico/rpi_pico_common.dtsi new file mode 100644 index 0000000000000..738cae8e7ae45 --- /dev/null +++ b/dts/arm/rpi_pico/rpi_pico_common.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef RPI_PICO_DEFAULT_IRQ_PRIORITY +#define RPI_PICO_DEFAULT_IRQ_PRIORITY 3 +#endif diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt new file mode 100644 index 0000000000000..78609df7a78a6 --- /dev/null +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_HAS_RPI_PICO) + zephyr_library() + + set(rp2_common_dir ${ZEPHYR_HAL_RPI_PICO_MODULE_DIR}/src/rp2_common) + set(rp2040_dir ${ZEPHYR_HAL_RPI_PICO_MODULE_DIR}/src/rp2040) + set(common_dir ${ZEPHYR_HAL_RPI_PICO_MODULE_DIR}/src/common) + set(boot_stage_dir ${rp2_common_dir}/boot_stage2) + + # Compile the second stage bootloader as a separate executable + + add_executable(boot_stage2) + + target_sources_ifdef(CONFIG_RP2_FLASH_W25Q080 boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_w25q080.S) + target_sources_ifdef(CONFIG_RP2_FLASH_GENERIC_03H boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_generic_03h.S) + target_sources_ifdef(CONFIG_RP2_FLASH_IS25LP080 boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_is25lp080.S) + target_sources_ifdef(CONFIG_RP2_FLASH_W25X10CL boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_w25x10cl.S) + + target_include_directories(boot_stage2 PUBLIC + ${CMAKE_CURRENT_LIST_DIR} + ${boot_stage_dir}/asminclude + ${rp2_common_dir}/pico_platform/include + ${rp2040_dir}/hardware_regs/include + ${common_dir}/pico_base/include + ) + + target_link_options(boot_stage2 PRIVATE + "-nostartfiles" + "--specs=nosys.specs" + "LINKER:--script=${boot_stage_dir}/boot_stage2.ld" + ) + + # Generates a binary file from the compiled bootloader + add_custom_target(bootloader_bin ALL DEPENDS boot_stage2.bin) + add_custom_command(OUTPUT boot_stage2.bin + DEPENDS boot_stage2 + COMMAND ${CMAKE_OBJCOPY} -Obinary $ boot_stage2.bin + ) + + # Checksums the binary, pads it, and generates an assembly file + add_custom_target(boot_stage2_asm ALL DEPENDS boot_stage2.S) + add_custom_command(OUTPUT boot_stage2.S + DEPENDS boot_stage2.bin + COMMAND ${Python3_EXECUTABLE} ${boot_stage_dir}/pad_checksum + -s 0xffffffff boot_stage2.bin boot_stage2.S) + + # Pico sources and headers necessary for every build. + # These contain definitions and implementation used mostly for + # initializing the SoC, and therefore are always required. + + zephyr_library_sources( + boot_stage2.S + ${rp2_common_dir}/hardware_clocks/clocks.c + ${rp2_common_dir}/hardware_pll/pll.c + ${rp2_common_dir}/hardware_xosc/xosc.c + ${rp2_common_dir}/hardware_watchdog/watchdog.c + ${rp2_common_dir}/pico_platform/platform.c + ) + + zephyr_include_directories( + ${rp2_common_dir}/hardware_base/include + ${rp2_common_dir}/hardware_clocks/include + ${rp2_common_dir}/hardware_watchdog/include + ${rp2_common_dir}/hardware_xosc/include + ${rp2_common_dir}/hardware_pll/include + ${rp2_common_dir}/hardware_irq/include + ${rp2_common_dir}/hardware_sync/include + ${rp2_common_dir}/hardware_timer/include + ${rp2_common_dir}/hardware_resets/include + ${rp2040_dir}/hardware_regs/include + ${rp2040_dir}/hardware_structs/include + ${common_dir}/pico_base/include + ${rp2_common_dir}/pico_platform/include + ${CMAKE_CURRENT_LIST_DIR} + ) + + zephyr_library_sources_ifdef(CONFIG_PICOSDK_USE_GPIO + ${rp2_common_dir}/hardware_gpio/gpio.c) + zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_GPIO + ${rp2_common_dir}/hardware_gpio/include) + + zephyr_library_sources_ifdef(CONFIG_PICOSDK_USE_UART + ${rp2_common_dir}/hardware_uart/uart.c) + zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_UART + ${rp2_common_dir}/hardware_uart/include) +endif() diff --git a/modules/hal_rpi_pico/Kconfig b/modules/hal_rpi_pico/Kconfig new file mode 100644 index 0000000000000..ebbe5b831977b --- /dev/null +++ b/modules/hal_rpi_pico/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +config HAS_RPI_PICO + bool + +config PICOSDK_USE_UART + bool + help + Use the UART driver from pico-sdk + +config PICOSDK_USE_GPIO + bool + help + Use the GPIO driver from pico-sdk diff --git a/modules/hal_rpi_pico/pico/config_autogen.h b/modules/hal_rpi_pico/pico/config_autogen.h new file mode 100644 index 0000000000000..95f4f52fff0cd --- /dev/null +++ b/modules/hal_rpi_pico/pico/config_autogen.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _CONFIG_AUTOGEN_H_ +#define _CONFIG_AUTOGEN_H_ + +/* WORKAROUNDS */ + +/* Use Zephyr's __asm macro instead of pico-sdk's asm */ +#define asm __asm + +/* pico-sdk uses static assertions, which fail the compilation */ +#define static_assert(...) + +/** + * pico-sdk expects __CONCAT to be defined, but we can't use + * Zephyr's sys/cdefs.h because this file is also included in + * assembly files. Therefore, we have to manually define __CONCAT + * only when it isn't defined, to avoid a conflict. + */ +#ifndef __CONCAT +#define __CAT(a, b) a ## b +#define __CONCAT(a, b) __CAT(a, b) +#endif /* __CONCAT */ + +/* Disable binary info */ +#define PICO_NO_BINARY_INFO 1 + +/* Zephyr compatible way of forcing inline */ +#ifndef __always_inline +#define __always_inline inline __attribute__((__always_inline__)) +#endif /* __always_inline */ + +/** + * Undefine the MHZ and KHZ defined by Zephyr, as they conflict + * with pico-sdk's definitions in clocks.h. + */ +#undef KHZ +#undef MHZ + +#endif diff --git a/modules/hal_rpi_pico/pico/version.h b/modules/hal_rpi_pico/pico/version.h new file mode 100644 index 0000000000000..00ea81156cb43 --- /dev/null +++ b/modules/hal_rpi_pico/pico/version.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* File intentionally left blank. It's expected by pico-sdk, but isn't used. */ diff --git a/soc/arm/rpi_pico/CMakeLists.txt b/soc/arm/rpi_pico/CMakeLists.txt new file mode 100644 index 0000000000000..226f3bd626f61 --- /dev/null +++ b/soc/arm/rpi_pico/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/arm/rpi_pico/Kconfig b/soc/arm/rpi_pico/Kconfig new file mode 100644 index 0000000000000..7d0f4215aad3f --- /dev/null +++ b/soc/arm/rpi_pico/Kconfig @@ -0,0 +1,18 @@ +# Raspberry Pi (RP) MCU line + +# Copyright (c) 2021 Nordic Semiconductor ASA +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_RPI_PICO + bool + +if SOC_FAMILY_RPI_PICO + +config SOC_FAMILY + string + default "rpi_pico" + +source "soc/arm/rpi_pico/*/Kconfig.soc" + +endif # SOC_FAMILY_RPI_PICO diff --git a/soc/arm/rpi_pico/Kconfig.defconfig b/soc/arm/rpi_pico/Kconfig.defconfig new file mode 100644 index 0000000000000..e05525f1aa1a8 --- /dev/null +++ b/soc/arm/rpi_pico/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Raspberry Pi (RP) MCU line + +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_RPI_PICO + +source "soc/arm/rpi_pico/*/Kconfig.defconfig.series" + +endif # SOC_FAMILY_RPI_PICO diff --git a/soc/arm/rpi_pico/Kconfig.soc b/soc/arm/rpi_pico/Kconfig.soc new file mode 100644 index 0000000000000..d53c18307e0d3 --- /dev/null +++ b/soc/arm/rpi_pico/Kconfig.soc @@ -0,0 +1,6 @@ +# Raspberry Pi (RP) MCU line + +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/rpi_pico/*/Kconfig.series" diff --git a/soc/arm/rpi_pico/rp2/CMakeLists.txt b/soc/arm/rpi_pico/rp2/CMakeLists.txt new file mode 100644 index 0000000000000..4f93d41e2068c --- /dev/null +++ b/soc/arm/rpi_pico/rp2/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources( + soc.c + rp2_init.c + ) diff --git a/soc/arm/rpi_pico/rp2/Kconfig.defconfig.rp2040 b/soc/arm/rpi_pico/rp2/Kconfig.defconfig.rp2040 new file mode 100644 index 0000000000000..a410181900c62 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/Kconfig.defconfig.rp2040 @@ -0,0 +1,8 @@ +# # Raspberry Pi RP2040 MCU + +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "rp2040" + depends on SOC_RP2040 diff --git a/soc/arm/rpi_pico/rp2/Kconfig.defconfig.series b/soc/arm/rpi_pico/rp2/Kconfig.defconfig.series new file mode 100644 index 0000000000000..7df057ae441b1 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/Kconfig.defconfig.series @@ -0,0 +1,17 @@ +# Raspberry Pi RP2XXX MCU line + +# Copyright (c) 2021 Nordic Semiconductor ASA +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RP2XXX + +source "soc/arm/rpi_pico/rp2/Kconfig.defconfig.rp2*" + +config SOC_SERIES + default "rp2" + +config NUM_IRQS + default 26 + +endif # SOC_SERIES_RP2XXX diff --git a/soc/arm/rpi_pico/rp2/Kconfig.series b/soc/arm/rpi_pico/rp2/Kconfig.series new file mode 100644 index 0000000000000..0c8c925f347f8 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/Kconfig.series @@ -0,0 +1,18 @@ +# Raspberry Pi RP2XXX MCU line + +# Copyright (c) 2021 Nordic Semiconductor ASA +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RP2XXX + bool "Raspberry Pi RP2 series MCU" + select ARM + select CPU_CORTEX_M0PLUS + select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR + select CPU_HAS_ARM_MPU + select SOC_FAMILY_RPI_PICO + select HAS_RPI_PICO + select XIP + help + Enable support for Raspberry Pi RP2 MCU series diff --git a/soc/arm/rpi_pico/rp2/Kconfig.soc b/soc/arm/rpi_pico/rp2/Kconfig.soc new file mode 100644 index 0000000000000..c52478c504c3f --- /dev/null +++ b/soc/arm/rpi_pico/rp2/Kconfig.soc @@ -0,0 +1,28 @@ +# Raspberry Pi RP2XXX MCU line + +# Copyright (c) 2021 Nordic Semiconductor ASA +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "RP2xxx MCU Selection" + depends on SOC_SERIES_RP2XXX + +config SOC_RP2040 + bool "Raspberry Pi RP2040" + +endchoice + +# Flash type used by the SoC. The board should select the one used. + +config RP2_FLASH_W25Q080 + bool + +config RP2_FLASH_GENERIC_03H + bool + +config RP2_FLASH_IS25LP080 + bool + +config RP2_FLASH_W25X10CL + bool diff --git a/soc/arm/rpi_pico/rp2/linker.ld b/soc/arm/rpi_pico/rp2/linker.ld new file mode 100644 index 0000000000000..c811fd921e210 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/linker.ld @@ -0,0 +1,22 @@ +/* linker.ld - Linker command/script file */ + +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +MEMORY +{ + BOOT_FLASH (r) : ORIGIN = 0x10000000, LENGTH = 256 +} + +SECTIONS +{ + .boot2 : { + KEEP(*(.boot2)) + } > BOOT_FLASH +} + +#include diff --git a/soc/arm/rpi_pico/rp2/rp2_init.c b/soc/arm/rpi_pico/rp2/rp2_init.c new file mode 100644 index 0000000000000..0b2db9291af11 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/rp2_init.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void rp2_init(void) +{ + reset_block(~(RESETS_RESET_IO_QSPI_BITS | + RESETS_RESET_PADS_QSPI_BITS | + RESETS_RESET_PLL_USB_BITS | + RESETS_RESET_PLL_SYS_BITS)); + + unreset_block_wait(RESETS_RESET_BITS & ~( + RESETS_RESET_ADC_BITS | + RESETS_RESET_RTC_BITS | + RESETS_RESET_SPI0_BITS | + RESETS_RESET_SPI1_BITS | + RESETS_RESET_UART0_BITS | + RESETS_RESET_UART1_BITS | + RESETS_RESET_USBCTRL_BITS)); + + clocks_init(); + + unreset_block_wait(RESETS_RESET_BITS); +} diff --git a/soc/arm/rpi_pico/rp2/soc.c b/soc/arm/rpi_pico/rp2/soc.c new file mode 100644 index 0000000000000..84f7a9bbd6799 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/soc.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for Raspberry Pi RP2040 family processor + * + * This module provides routines to initialize and support board-level hardware + * for the Raspberry Pi RP2040 family processor. + */ + +#include +#include +#include + + +#ifdef CONFIG_RUNTIME_NMI +extern void z_arm_nmi_init(void); +#define NMI_INIT() z_arm_nmi_init() +#else +#define NMI_INIT() +#endif + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +void rp2_init(void); + +static int rpi_rp2040_init(const struct device *arg) +{ + uint32_t key; + + rp2_init(); + + ARG_UNUSED(arg); + + key = irq_lock(); + + /* Install default handler that simply resets the CPU + * if configured in the kernel, NOP otherwise + */ + NMI_INIT(); + + irq_unlock(key); + + return 0; +} + +SYS_INIT(rpi_rp2040_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/rpi_pico/rp2/soc.h b/soc/arm/rpi_pico/rp2/soc.h new file mode 100644 index 0000000000000..100145df438d8 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/soc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 Linaro Limited + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the Raspberry Pi RP2040 family processors + */ + +#ifndef _RPI_PICO_RP2040_SOC_H_ +#define _RPI_PICO_RP2040_SOC_H_ + +#define __VTOR_PRESENT 1 +#define __MPU_PRESENT 1 + +#endif /* _RPI_PICO_RP2040_SOC_H_ */ From e192922c972550db22b6e8b0ac6a594af9f5762f Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Tue, 30 Nov 2021 00:29:09 +0200 Subject: [PATCH 3/8] drivers: pinctrl: Added pinctrl driver for RPi Pico Added a pinctrl driver for the Raspberry Pi Pico series Signed-off-by: Yonatan Schachter --- CODEOWNERS | 1 + drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.rpi_pico | 12 ++ drivers/pinctrl/pinctrl_rpi_pico.c | 34 +++++ dts/arm/rpi_pico/rp2040.dtsi | 7 + .../pinctrl/raspberrypi,pico-pinctrl.yaml | 123 ++++++++++++++++++ .../pinctrl/rpi-pico-rp2040-pinctrl.h | 62 +++++++++ soc/arm/rpi_pico/Kconfig.defconfig | 3 + soc/arm/rpi_pico/rp2/pinctrl_soc.h | 71 ++++++++++ 10 files changed, 315 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.rpi_pico create mode 100644 drivers/pinctrl/pinctrl_rpi_pico.c create mode 100644 dts/bindings/pinctrl/raspberrypi,pico-pinctrl.yaml create mode 100644 include/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h create mode 100644 soc/arm/rpi_pico/rp2/pinctrl_soc.h diff --git a/CODEOWNERS b/CODEOWNERS index 99bd78ebeb0aa..e925e35cb40e3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -486,6 +486,7 @@ /dts/bindings/*/nordic* @anangl /dts/bindings/*/nxp* @mmahadevan108 @dleach02 /dts/bindings/*/openisa* @dleach02 +/dts/bindings/*/raspberrypi*pico* @yonsch /dts/bindings/*/st* @erwango /dts/bindings/sensor/ams* @alexanderwachter /dts/bindings/*/sifive* @mateusz-holenko @kgugala @pgielda diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index a14936b479dd8..79d0eaa6b372a 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -7,4 +7,5 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AFIO pinctrl_gd32_afio.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NRF pinctrl_nrf.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RCAR_PFC pfc_rcar.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_RPI_PICO pinctrl_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_STM32 pinctrl_stm32.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 8162329175028..8680acc3234ec 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -32,6 +32,7 @@ config PINCTRL_DYNAMIC source "drivers/pinctrl/Kconfig.gd32" source "drivers/pinctrl/Kconfig.nrf" source "drivers/pinctrl/Kconfig.rcar" +source "drivers/pinctrl/Kconfig.rpi_pico" source "drivers/pinctrl/Kconfig.stm32" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.rpi_pico b/drivers/pinctrl/Kconfig.rpi_pico new file mode 100644 index 0000000000000..066e05eb0f516 --- /dev/null +++ b/drivers/pinctrl/Kconfig.rpi_pico @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +DT_COMPAT_RPI_PICO_PINCTRL := raspberrypi,pico-pinctrl + +config PINCTRL_RPI_PICO + bool "RaspberryPi Pico pin controller driver" + depends on SOC_FAMILY_RPI_PICO + default $(dt_compat_enabled,$(DT_COMPAT_RPI_PICO_PINCTRL)) + select PICOSDK_USE_GPIO + help + RaspberryPi Pico pinctrl driver diff --git a/drivers/pinctrl/pinctrl_rpi_pico.c b/drivers/pinctrl/pinctrl_rpi_pico.c new file mode 100644 index 0000000000000..8a51cd4e6b8b9 --- /dev/null +++ b/drivers/pinctrl/pinctrl_rpi_pico.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* pico-sdk includes */ +#include + +static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) +{ + gpio_init(pin->pin_num); + gpio_set_function(pin->pin_num, pin->alt_func); + gpio_set_pulls(pin->pin_num, pin->pullup, pin->pulldown); + gpio_set_drive_strength(pin->pin_num, pin->drive_strength); + gpio_set_slew_rate(pin->pin_num, (pin->slew_rate ? + GPIO_SLEW_RATE_FAST : GPIO_SLEW_RATE_SLOW)); + gpio_set_input_hysteresis_enabled(pin->pin_num, pin->schmitt_enable); + gpio_set_input_enabled(pin->pin_num, pin->input_enable); +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, + uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + pinctrl_configure_pin(pins++); + } + + return 0; +} diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index b0714f02157c8..9cbe7c4f50be9 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -43,6 +43,13 @@ clock-frequency = <125000000>; #clock-cells = <0>; }; + + pinctrl: pin-controller@40014000 { + compatible = "raspberrypi,pico-pinctrl"; + reg = <0x40014000 DT_SIZE_K(4)>; + status = "okay"; + label = "PINCTRL"; + }; }; }; diff --git a/dts/bindings/pinctrl/raspberrypi,pico-pinctrl.yaml b/dts/bindings/pinctrl/raspberrypi,pico-pinctrl.yaml new file mode 100644 index 0000000000000..dbd43713dea2c --- /dev/null +++ b/dts/bindings/pinctrl/raspberrypi,pico-pinctrl.yaml @@ -0,0 +1,123 @@ +# Copyright (c) 2021 Teslabs Engineering S.L. +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +description: | + The RPi Pico pin controller is a node responsible for controlling + pin function selection and pin properties, such as routing a UART0 Rx + to pin 1 and enabling the pullup resistor on that pin. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as shown in this example: + + /* You can put this in places like a board-pinctrl.dtsi file in + * your board directory, or a devicetree overlay in your application. + */ + + /* include pre-defined combinations for the SoC variant used by the board */ + #include + + &pinctrl { + /* configuration for the usart0 "default" state */ + uart0_default: uart0_default { + /* group 1 */ + group1 { + /* configure P0 as UART0 TX */ + pinmux = ; + }; + /* group 2 */ + group2 { + /* configure P1 as UART0 RX */ + pinmux = ; + /* enable input on pin 1 */ + input-enable; + }; + }; + }; + + The 'uart0_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. + + As shown, pin configurations are organized in groups within each child node. + Each group can specify a list of pin function selections in the 'pinmux' + property. + + A group can also specify shared pin properties common to all the specified + pins, such as the 'input-enable' property in group 2. Here is a list of + supported standard pin properties: + + - bias-disable: Disable pull-up/down (default, not required). + - bias-pull-up: Enable pull-up resistor. + - bias-pull-down: Enable pull-down resistor. + - input-enable: Enable input from the pin. + - input-schmitt-enable: Enable input hysteresys. + - drive-strength: Set the drive strength of the pin, in milliamps. Possible + values are: 2, 4, 8, 12 (default: 4mA) + - slew-rate: If set to 0, slew rate is set to slow. If set to 1, it is set + to fast. + + To link pin configurations with a device, use a pinctrl-N property for some + number N, like this example you could place in your board's DTS file: + + #include "board-pinctrl.dtsi" + + &uart0 { + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; + }; + +compatible: "raspberrypi,pico-pinctrl" + +include: + - name: base.yaml + - name: pincfg-node-group.yaml + child-binding: + child-binding: + property-allowlist: + - bias-disable + - bias-pull-down + - bias-pull-up + - input-enable + - input-schmitt-enable + - drive-strength + - slew-rate + +child-binding: + description: | + Definitions for a pinctrl state. + child-binding: + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. Each + element of the array is an integer constructed from the + pin number and the alternative function of the pin. + drive-strength: + enum: + - 2 + - 4 + - 8 + - 12 + default: 4 + description: | + The drive strength of a pin, in mA. The default value is 4mA, as this + is the power on reset value. + slew-rate: + enum: + - 0 + - 1 + default: 0 + description: | + The slew rate of a pin. 0 corresponds to slow, and 1 corresponds to fast. + The default value is 0 (slow), as this is the power on reset value. diff --git a/include/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h b/include/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h new file mode 100644 index 0000000000000..b01637c34f83f --- /dev/null +++ b/include/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RP2040_PINCTRL_H__ +#define __RP2040_PINCTRL_H__ + +#define PINCTRL_GPIO_FUNC_XIP 0 +#define PINCTRL_GPIO_FUNC_SPI 1 +#define PINCTRL_GPIO_FUNC_UART 2 +#define PINCTRL_GPIO_FUNC_I2C 3 +#define PINCTRL_GPIO_FUNC_PWM 4 +#define PINCTRL_GPIO_FUNC_SIO 5 +#define PINCTRL_GPIO_FUNC_PIO0 6 +#define PINCTRL_GPIO_FUNC_PIO1 7 +#define PINCTRL_GPIO_FUNC_GPCK 8 +#define PINCTRL_GPIO_FUNC_USB 9 +#define PINCTRL_GPIO_FUNC_NULL 0xf + +#define ALT_FUNC_POS 0 +#define ALT_FUNC_MASK 0xf + +#define PIN_NUM_POS 4 +#define PIN_NUM_MASK 0x1f + +#define RP2040_PINMUX(pin_num, alt_func) (pin_num << PIN_NUM_POS | \ + alt_func << ALT_FUNC_POS) + +#define UART0_TX_P0 RP2040_PINMUX(0, PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P1 RP2040_PINMUX(1, PINCTRL_GPIO_FUNC_UART) +#define UART0_CTS_P2 RP2040_PINMUX(2, PINCTRL_GPIO_FUNC_UART) +#define UART0_RTS_P3 RP2040_PINMUX(3, PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P4 RP2040_PINMUX(4, PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P5 RP2040_PINMUX(5, PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P6 RP2040_PINMUX(6, PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P7 RP2040_PINMUX(7, PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P8 RP2040_PINMUX(8, PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P9 RP2040_PINMUX(9, PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P10 RP2040_PINMUX(10, PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P11 RP2040_PINMUX(11, PINCTRL_GPIO_FUNC_UART) +#define UART0_TX_P12 RP2040_PINMUX(12, PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P13 RP2040_PINMUX(13, PINCTRL_GPIO_FUNC_UART) +#define UART0_CTS_P14 RP2040_PINMUX(14, PINCTRL_GPIO_FUNC_UART) +#define UART0_RTS_P15 RP2040_PINMUX(15, PINCTRL_GPIO_FUNC_UART) +#define UART0_TX_P16 RP2040_PINMUX(16, PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P17 RP2040_PINMUX(17, PINCTRL_GPIO_FUNC_UART) +#define UART0_CTS_P18 RP2040_PINMUX(18, PINCTRL_GPIO_FUNC_UART) +#define UART0_RTS_P19 RP2040_PINMUX(19, PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P20 RP2040_PINMUX(20, PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P21 RP2040_PINMUX(21, PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P22 RP2040_PINMUX(22, PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P23 RP2040_PINMUX(23, PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P24 RP2040_PINMUX(24, PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P25 RP2040_PINMUX(25, PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P26 RP2040_PINMUX(26, PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P27 RP2040_PINMUX(27, PINCTRL_GPIO_FUNC_UART) +#define UART0_TX_P28 RP2040_PINMUX(28, PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P29 RP2040_PINMUX(29, PINCTRL_GPIO_FUNC_UART) + +#endif /* __RP2040_PINCTRL_H__ */ diff --git a/soc/arm/rpi_pico/Kconfig.defconfig b/soc/arm/rpi_pico/Kconfig.defconfig index e05525f1aa1a8..468d4545c5b23 100644 --- a/soc/arm/rpi_pico/Kconfig.defconfig +++ b/soc/arm/rpi_pico/Kconfig.defconfig @@ -7,4 +7,7 @@ if SOC_FAMILY_RPI_PICO source "soc/arm/rpi_pico/*/Kconfig.defconfig.series" +config PINCTRL + default y + endif # SOC_FAMILY_RPI_PICO diff --git a/soc/arm/rpi_pico/rp2/pinctrl_soc.h b/soc/arm/rpi_pico/rp2/pinctrl_soc.h new file mode 100644 index 0000000000000..bff3cbda11d21 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/pinctrl_soc.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_RPI_PICO_RP2_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RPI_PICO_RP2_PINCTRL_SOC_H_ + +#include + +/** + * @brief Type to hold a pin's pinctrl configuration. + */ +struct rpi_pinctrl_soc_pin { + /** Pin number 0..29 */ + uint32_t pin_num : 5; + /** Alternative function (UART, SPI, etc.) */ + uint32_t alt_func : 4; + /** Maximum current used by a pin, in mA */ + uint32_t drive_strength : 4; + /** Slew rate, may be either false (slow) or true (fast) */ + uint32_t slew_rate : 1; + /** Enable the internal pull up resistor */ + uint32_t pullup : 1; + /** Enable the internal pull down resistor */ + uint32_t pulldown : 1; + /** Enable the pin as an input */ + uint32_t input_enable : 1; + /** Enable the internal schmitt trigger */ + uint32_t schmitt_enable : 1; +}; + +typedef struct rpi_pinctrl_soc_pin pinctrl_soc_pin_t; + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param prop Property name. + * @param idx Property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + RP2_GET_PIN_NUM(DT_PROP_BY_IDX(node_id, prop, idx)), \ + RP2_GET_PIN_ALT_FUNC(DT_PROP_BY_IDX(node_id, prop, idx)), \ + DT_ENUM_IDX(node_id, drive_strength), \ + DT_ENUM_IDX(node_id, slew_rate), \ + DT_PROP(node_id, bias_pull_up), \ + DT_PROP(node_id, bias_pull_down), \ + DT_PROP(node_id, input_enable), \ + DT_PROP(node_id, input_schmitt_enable), \ + }, + +/** + * @brief Utility macro to initialize state pins contained in a given property. + * + * @param node_id Node identifier. + * @param prop Property name describing state pins. + */ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT)} + +#define RP2_GET_PIN_NUM(pinctrl) \ + (((pinctrl) >> PIN_NUM_POS) & PIN_NUM_MASK) +#define RP2_GET_PIN_ALT_FUNC(pinctrl) \ + (((pinctrl) >> ALT_FUNC_POS) & ALT_FUNC_MASK) + +#endif /* ZEPHYR_SOC_ARM_RPI_PICO_RP2_PINCTRL_SOC_H_ */ From ef401147433063e1520bd37d4658a3ccc8fa2756 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Tue, 30 Nov 2021 00:40:43 +0200 Subject: [PATCH 4/8] drivers: serial: Added support for raspberry pi Added a serial driver for the RP2040. Only polling API is supported. Signed-off-by: Yonatan Schachter --- CODEOWNERS | 1 + drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.rpi_pico | 11 +++ drivers/serial/uart_rpi_pico.c | 75 +++++++++++++++++++ dts/arm/rpi_pico/rp2040.dtsi | 20 +++++ .../serial/raspberrypi,pico-uart.yaml | 12 +++ 7 files changed, 122 insertions(+) create mode 100644 drivers/serial/Kconfig.rpi_pico create mode 100644 drivers/serial/uart_rpi_pico.c create mode 100644 dts/bindings/serial/raspberrypi,pico-uart.yaml diff --git a/CODEOWNERS b/CODEOWNERS index e925e35cb40e3..927cd4926665e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -350,6 +350,7 @@ /drivers/serial/uart_mcux_iuart.c @Mani-Sadhasivam /drivers/serial/Kconfig.rtt @carlescufi @pkral78 /drivers/serial/uart_rtt.c @carlescufi @pkral78 +/drivers/serial/*rpi_pico* @yonsch /drivers/serial/Kconfig.xlnx @wjliang /drivers/serial/uart_xlnx_ps.c @wjliang /drivers/serial/uart_xlnx_uartlite.c @henrikbrixandersen diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index acb5195d73a4a..5eef4eab5ff77 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -32,6 +32,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_SAM0 uart_sam0.c) zephyr_library_sources_ifdef(CONFIG_UART_PSOC6 uart_psoc6.c) zephyr_library_sources_ifdef(CONFIG_UART_PL011 uart_pl011.c) zephyr_library_sources_ifdef(CONFIG_UART_RV32M1_LPUART uart_rv32m1_lpuart.c) +zephyr_library_sources_ifdef(CONFIG_UART_RPI_PICO uart_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_UART_LITEUART uart_liteuart.c) zephyr_library_sources_ifdef(CONFIG_UART_RTT_DRIVER uart_rtt.c) zephyr_library_sources_ifdef(CONFIG_UART_XLNX_PS uart_xlnx_ps.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 2455174ae4280..3d110543d92f1 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -159,6 +159,8 @@ source "drivers/serial/Kconfig.pl011" source "drivers/serial/Kconfig.rv32m1_lpuart" +source "drivers/serial/Kconfig.rpi_pico" + source "drivers/serial/Kconfig.litex" source "drivers/serial/Kconfig.rtt" diff --git a/drivers/serial/Kconfig.rpi_pico b/drivers/serial/Kconfig.rpi_pico new file mode 100644 index 0000000000000..bab871be581b0 --- /dev/null +++ b/drivers/serial/Kconfig.rpi_pico @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +# Workaround for not being able to have commas in macro arguments +DT_COMPAT_RPI_PICO_UART := raspberrypi,pico-uart + +config UART_RPI_PICO + bool "Raspberry Pi UART driver" + default $(dt_compat_enabled,$(DT_COMPAT_RPI_PICO_UART)) + select SERIAL_HAS_DRIVER + select PICOSDK_USE_UART diff --git a/drivers/serial/uart_rpi_pico.c b/drivers/serial/uart_rpi_pico.c new file mode 100644 index 0000000000000..b0f4e28034545 --- /dev/null +++ b/drivers/serial/uart_rpi_pico.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* pico-sdk includes */ +#include + +#define DT_DRV_COMPAT raspberrypi_pico_uart + +struct uart_rpi_config { + uart_inst_t *const uart_dev; + uint32_t baudrate; + const struct pinctrl_dev_config *pcfg; +}; + +static int uart_rpi_poll_in(const struct device *dev, unsigned char *c) +{ + const struct uart_rpi_config *config = dev->config; + + if (!uart_is_readable(config->uart_dev)) { + return -1; + } + + *c = (unsigned char)uart_get_hw(config->uart_dev)->dr; + return 0; +} + +static void uart_rpi_poll_out(const struct device *dev, unsigned char c) +{ + const struct uart_rpi_config *config = dev->config; + + uart_putc_raw(config->uart_dev, c); +} + +static int uart_rpi_init(const struct device *dev) +{ + const struct uart_rpi_config *config = dev->config; + int ret; + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + uart_init(config->uart_dev, config->baudrate); + + return 0; +} + +static const struct uart_driver_api uart_rpi_driver_api = { + .poll_in = uart_rpi_poll_in, + .poll_out = uart_rpi_poll_out, +}; + +#define RPI_UART_INIT(idx) \ + PINCTRL_DT_INST_DEFINE(idx); \ + static const struct uart_rpi_config uart_rpi_cfg_##idx = { \ + .uart_dev = (uart_inst_t *)DT_INST_REG_ADDR(idx), \ + .baudrate = DT_INST_PROP(idx, current_speed), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, &uart_rpi_init, \ + NULL, \ + NULL, \ + &uart_rpi_cfg_##idx, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_rpi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RPI_UART_INIT) diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index 9cbe7c4f50be9..dd48076e02be5 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -50,6 +50,26 @@ status = "okay"; label = "PINCTRL"; }; + + uart0: uart@40034000 { + compatible = "raspberrypi,pico-uart"; + reg = <0x40034000 DT_SIZE_K(4)>; + clocks = <&peripheral_clk>; + interrupts = <20 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + interrupt-names = "uart0"; + label = "UART_0"; + status = "disabled"; + }; + + uart1: uart@40038000 { + compatible = "raspberrypi,pico-uart"; + reg = <0x40038000 DT_SIZE_K(4)>; + clocks = <&peripheral_clk>; + interrupts = <21 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + interrupt-names = "uart1"; + label = "UART_1"; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/serial/raspberrypi,pico-uart.yaml b/dts/bindings/serial/raspberrypi,pico-uart.yaml new file mode 100644 index 0000000000000..50c3bd44d741e --- /dev/null +++ b/dts/bindings/serial/raspberrypi,pico-uart.yaml @@ -0,0 +1,12 @@ +description: Raspberry Pi Pico UART + +compatible: "raspberrypi,pico-uart" + +include: [uart-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true From 79ada6967cef85910c4ba1e3e20038d38fbf37a2 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Tue, 30 Nov 2021 00:49:38 +0200 Subject: [PATCH 5/8] drivers: gpio: Added support for raspberry pi Added GPIO support for the RP2040 SoC. Only one core is supported. Signed-off-by: Yonatan Schachter --- CODEOWNERS | 1 + drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.rpi_pico | 10 + drivers/gpio/gpio_rpi_pico.c | 192 +++++++++++++++++++ dts/arm/rpi_pico/rp2040.dtsi | 11 ++ dts/bindings/gpio/raspberrypi,pico-gpio.yaml | 22 +++ scripts/checkpatch/typedefsfile | 1 + 8 files changed, 240 insertions(+) create mode 100644 drivers/gpio/Kconfig.rpi_pico create mode 100644 drivers/gpio/gpio_rpi_pico.c create mode 100644 dts/bindings/gpio/raspberrypi,pico-gpio.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 927cd4926665e..c2ff75c6e56df 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -263,6 +263,7 @@ /drivers/gpio/*eos_s3* @wtatarski @kowalewskijan @kgugala /drivers/gpio/*rcar* @julien-massot /drivers/gpio/*esp32* @glaubermaroto +/drivers/gpio/*rpi_pico* @yonsch /drivers/hwinfo/ @alexanderwachter /drivers/i2c/i2c_common.c @sjg20 /drivers/i2c/i2c_emul.c @sjg20 diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 32412257a2fd7..af23733f36831 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -30,6 +30,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SAM4L gpio_sam4l.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SX1509B gpio_sx1509b.c) zephyr_library_sources_ifdef(CONFIG_GPIO_INTEL gpio_intel.c) zephyr_library_sources_ifdef(CONFIG_GPIO_STELLARIS gpio_stellaris.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RPI_PICO gpio_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RV32M1 gpio_rv32m1.c) zephyr_library_sources_ifdef(CONFIG_GPIO_LMP90XXX gpio_lmp90xxx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_LITEX gpio_litex.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ccec99316a9d6..7ff6931a3717b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -77,6 +77,8 @@ source "drivers/gpio/Kconfig.xec" source "drivers/gpio/Kconfig.stellaris" +source "drivers/gpio/Kconfig.rpi_pico" + source "drivers/gpio/Kconfig.rv32m1" source "drivers/gpio/Kconfig.lmp90xxx" diff --git a/drivers/gpio/Kconfig.rpi_pico b/drivers/gpio/Kconfig.rpi_pico new file mode 100644 index 0000000000000..8bd1488d74f6c --- /dev/null +++ b/drivers/gpio/Kconfig.rpi_pico @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +# Workaround for not being able to have commas in macro arguments +DT_COMPAT_RPI_PICO_GPIO := raspberrypi,pico-gpio + +config GPIO_RPI_PICO + default $(dt_compat_enabled,$(DT_COMPAT_RPI_PICO_GPIO)) + select PICOSDK_USE_GPIO + bool "Raspberry Pi Pico GPIO driver" diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c new file mode 100644 index 0000000000000..e66673c6cb337 --- /dev/null +++ b/drivers/gpio/gpio_rpi_pico.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* pico-sdk includes */ +#include +#include +#include + +#include "gpio_utils.h" + +#define DT_DRV_COMPAT raspberrypi_pico_gpio + +#define ALL_EVENTS (GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE \ + | GPIO_IRQ_LEVEL_LOW | GPIO_IRQ_LEVEL_HIGH) + +struct gpio_rpi_config { + struct gpio_driver_config common; + void (*bank_config_func)(void); +}; + +struct gpio_rpi_data { + struct gpio_driver_data common; + sys_slist_t callbacks; + uint32_t int_enabled_mask; +}; + +static int gpio_rpi_configure(const struct device *dev, + gpio_pin_t pin, + gpio_flags_t flags) +{ + if (flags & GPIO_SINGLE_ENDED) { + return -ENOTSUP; + } + + gpio_init(pin); + + if (flags & GPIO_OUTPUT) { + gpio_set_dir(pin, GPIO_OUT); + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + gpio_put(pin, 1); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + gpio_put(pin, 0); + } + } else if (flags & GPIO_INPUT) { + gpio_set_dir(pin, GPIO_IN); + if (flags & GPIO_PULL_UP) { + gpio_pull_up(pin); + } else if (flags & GPIO_PULL_DOWN) { + gpio_pull_down(pin); + } + } + + return 0; +} + +static int gpio_rpi_port_get_raw(const struct device *dev, uint32_t *value) +{ + *value = gpio_get_all(); + return 0; +} + +static int gpio_rpi_port_set_masked_raw(const struct device *port, + uint32_t mask, uint32_t value) +{ + gpio_put_masked(mask, value); + return 0; +} + +static int gpio_rpi_port_set_bits_raw(const struct device *port, + uint32_t pins) +{ + gpio_set_mask(pins); + return 0; +} + +static int gpio_rpi_port_clear_bits_raw(const struct device *port, + uint32_t pins) +{ + gpio_clr_mask(pins); + return 0; +} + +static int gpio_rpi_port_toggle_bits(const struct device *port, + uint32_t pins) +{ + gpio_xor_mask(pins); + return 0; +} + +static int gpio_rpi_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + struct gpio_rpi_data *data = dev->data; + uint32_t events = 0; + + if (mode != GPIO_INT_DISABLE) { + if (mode & GPIO_INT_EDGE) { + if (trig & GPIO_INT_LOW_0) { + events |= GPIO_IRQ_EDGE_FALL; + } + if (trig & GPIO_INT_HIGH_1) { + events |= GPIO_IRQ_EDGE_RISE; + } + } else { + if (trig & GPIO_INT_LOW_0) { + events |= GPIO_IRQ_LEVEL_LOW; + } + if (trig & GPIO_INT_HIGH_1) { + events |= GPIO_IRQ_LEVEL_HIGH; + } + } + gpio_set_irq_enabled(pin, events, true); + } + WRITE_BIT(data->int_enabled_mask, pin, mode != GPIO_INT_DISABLE); + return 0; +} + +static int gpio_rpi_manage_callback(const struct device *dev, + struct gpio_callback *callback, bool set) +{ + struct gpio_rpi_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static const struct gpio_driver_api gpio_rpi_driver_api = { + .pin_configure = gpio_rpi_configure, + .port_get_raw = gpio_rpi_port_get_raw, + .port_set_masked_raw = gpio_rpi_port_set_masked_raw, + .port_set_bits_raw = gpio_rpi_port_set_bits_raw, + .port_clear_bits_raw = gpio_rpi_port_clear_bits_raw, + .port_toggle_bits = gpio_rpi_port_toggle_bits, + .pin_interrupt_configure = gpio_rpi_pin_interrupt_configure, + .manage_callback = gpio_rpi_manage_callback, +}; + +static void gpio_rpi_isr(const struct device *dev) +{ + struct gpio_rpi_data *data = dev->data; + io_irq_ctrl_hw_t *irq_ctrl_base; + const io_rw_32 *status_reg; + uint32_t events; + uint32_t pin; + + irq_ctrl_base = &iobank0_hw->proc0_irq_ctrl; + for (pin = 0; pin < NUM_BANK0_GPIOS; pin++) { + status_reg = &irq_ctrl_base->ints[pin / 8]; + events = (*status_reg >> 4 * (pin % 8)) & ALL_EVENTS; + if (events) { + gpio_acknowledge_irq(pin, ALL_EVENTS); + gpio_fire_callbacks(&data->callbacks, dev, BIT(pin)); + } + } +} + +static int gpio_rpi_bank_init(const struct device *dev) +{ + const struct gpio_rpi_config *config = dev->config; + + config->bank_config_func(); + return 0; +} + +#define GPIO_RPI_INIT(idx) \ +static void bank_##idx##_config_func(void) \ +{ \ + IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), \ + gpio_rpi_isr, DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_INST_IRQN(idx)); \ +} \ +static const struct gpio_rpi_config gpio_rpi_##idx##_config = { \ + .bank_config_func = bank_##idx##_config_func, \ +}; \ + \ +static struct gpio_rpi_data gpio_rpi_##idx##_data; \ + \ +DEVICE_DT_INST_DEFINE(idx, gpio_rpi_bank_init, NULL, \ + &gpio_rpi_##idx##_data, \ + &gpio_rpi_##idx##_config, \ + POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_rpi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_RPI_INIT) diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index dd48076e02be5..72d6efeb712c5 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -5,6 +5,7 @@ */ #include +#include #include #include "rpi_pico_common.dtsi" @@ -51,6 +52,16 @@ label = "PINCTRL"; }; + gpio0: gpio@40014000 { + compatible = "raspberrypi,pico-gpio"; + reg = <0x40014000 DT_SIZE_K(4)>; + interrupts = <13 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + gpio-controller; + #gpio-cells = <2>; + label = "GPIO_0"; + status = "disabled"; + }; + uart0: uart@40034000 { compatible = "raspberrypi,pico-uart"; reg = <0x40034000 DT_SIZE_K(4)>; diff --git a/dts/bindings/gpio/raspberrypi,pico-gpio.yaml b/dts/bindings/gpio/raspberrypi,pico-gpio.yaml new file mode 100644 index 0000000000000..ab987ecb75889 --- /dev/null +++ b/dts/bindings/gpio/raspberrypi,pico-gpio.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2021, Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +description: Raspberry Pi Pico GPIO + +compatible: "raspberrypi,pico-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/scripts/checkpatch/typedefsfile b/scripts/checkpatch/typedefsfile index 7e030b5b97b00..ef5109b14747f 100644 --- a/scripts/checkpatch/typedefsfile +++ b/scripts/checkpatch/typedefsfile @@ -3,3 +3,4 @@ k_mem_partition_attr_t mbedtls_pk_context z_arch_esf_t pinctrl_soc_pin_t +io_rw_32 From c81e6ba2c1d27dcc349e5e18d6f4c70fb4cec460 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Tue, 30 Nov 2021 00:05:15 +0200 Subject: [PATCH 6/8] boards: Added support for the Raspberry Pi Pico board Added support for Raspberry Pi's Pico board, using the RP2040 SoC. Signed-off-by: Yonatan Schachter --- CODEOWNERS | 1 + boards/arm/rpi_pico/Kconfig.board | 6 ++ boards/arm/rpi_pico/Kconfig.defconfig | 12 ++++ boards/arm/rpi_pico/board.cmake | 0 boards/arm/rpi_pico/doc/img/rpi_pico.png | Bin 0 -> 139396 bytes boards/arm/rpi_pico/doc/index.rst | 59 ++++++++++++++++++ boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi | 18 ++++++ boards/arm/rpi_pico/rpi_pico.dts | 69 ++++++++++++++++++++++ boards/arm/rpi_pico/rpi_pico.yaml | 10 ++++ boards/arm/rpi_pico/rpi_pico_defconfig | 8 +++ 10 files changed, 183 insertions(+) create mode 100644 boards/arm/rpi_pico/Kconfig.board create mode 100644 boards/arm/rpi_pico/Kconfig.defconfig create mode 100644 boards/arm/rpi_pico/board.cmake create mode 100644 boards/arm/rpi_pico/doc/img/rpi_pico.png create mode 100644 boards/arm/rpi_pico/doc/index.rst create mode 100644 boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi create mode 100644 boards/arm/rpi_pico/rpi_pico.dts create mode 100644 boards/arm/rpi_pico/rpi_pico.yaml create mode 100644 boards/arm/rpi_pico/rpi_pico_defconfig diff --git a/CODEOWNERS b/CODEOWNERS index c2ff75c6e56df..8e4054f5e3d9f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -128,6 +128,7 @@ /boards/arm/quick_feather/ @kowalewskijan @kgugala /boards/arm/rak4631_nrf52840/ @gpaquet85 /boards/arm/rak5010_nrf52840/ @gpaquet85 +/boards/arm/rpi_pico/ @yonsch /boards/arm/ronoth_lodev/ @NorthernDean /boards/arm/xmc45_relax_kit/ @parthitce /boards/arm/sam4e_xpro/ @nandojve diff --git a/boards/arm/rpi_pico/Kconfig.board b/boards/arm/rpi_pico/Kconfig.board new file mode 100644 index 0000000000000..ac9d9661bbfe4 --- /dev/null +++ b/boards/arm/rpi_pico/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RPI_PICO + bool "Raspberry Pi Pico Board" + depends on SOC_RP2040 diff --git a/boards/arm/rpi_pico/Kconfig.defconfig b/boards/arm/rpi_pico/Kconfig.defconfig new file mode 100644 index 0000000000000..859efc0fdd30c --- /dev/null +++ b/boards/arm/rpi_pico/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RPI_PICO + +config BOARD + default "rpi_pico" + +config RP2_FLASH_W25Q080 + default y + +endif # BOARD_RPI_PICO diff --git a/boards/arm/rpi_pico/board.cmake b/boards/arm/rpi_pico/board.cmake new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/boards/arm/rpi_pico/doc/img/rpi_pico.png b/boards/arm/rpi_pico/doc/img/rpi_pico.png new file mode 100644 index 0000000000000000000000000000000000000000..0b223bb334bd9eb361431363c89ae00a9eb746d8 GIT binary patch literal 139396 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®xJ43J{s%WDJ+72*QhQS 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

gWn^Cf6)#tjPSP) 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 literal 0 HcmV?d00001 diff --git a/boards/arm/rpi_pico/doc/index.rst b/boards/arm/rpi_pico/doc/index.rst new file mode 100644 index 0000000000000..ef0d7cfd8b89d --- /dev/null +++ b/boards/arm/rpi_pico/doc/index.rst @@ -0,0 +1,59 @@ +.. _rpi_pico: + +Raspberry Pi Pico +################# + +Overview +******** + +The Raspberry Pi Pico is a small, low-cost, versatile board from +Raspberry Pi. It is equipped with an RP2040 SoC, an on-board LED, +a USB connector, and an SWD interface. The USB bootloader allows it +to be flashed without any adapter, in a drag-and-drop manner. +It is also possible to flash and debug the Pico with its SWD interface, +using an external adapter. + +Hardware +******** +- Dual core Arm Cortex-M0+ processor running up to 133MHz +- 264KB on-chip SRAM +- 2MB on-board QSPI flash with XIP capabilities +- 26 GPIO pins +- 3 Analog inputs +- 2 UART peripherals +- 2 SPI controllers +- 2 I2C controllers +- 16 PWM channels +- USB 1.1 controller (host/device) +- 8 Programmable I/O (PIO) for custom peripherals +- On-board LED + + +.. figure:: img/rpi_pico.png + :width: 150px + :align: center + :alt: Raspberry Pi Pico + + Raspberry Pi Pico (Image courtesy of Raspberry Pi) + +Supported Features +================== + +The rpi_pico board configuration supports the following +hardware features: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - NVIC + - N/A + - :dtcompatible:`arm,v6m-nvic` + * - UART + - :kconfig:`CONFIG_SERIAL` + - :dtcompatible:`rpi,pico-uart` + * - GPIO + - :kconfig:`CONFIG_GPIO` + - :dtcompatible:`rpi,pico-gpio` diff --git a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi new file mode 100644 index 0000000000000..f20558729c4bd --- /dev/null +++ b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; +}; diff --git a/boards/arm/rpi_pico/rpi_pico.dts b/boards/arm/rpi_pico/rpi_pico.dts new file mode 100644 index 0000000000000..050df862a1209 --- /dev/null +++ b/boards/arm/rpi_pico/rpi_pico.dts @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "rpi_pico-pinctrl.dtsi" + +/ { + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,code-partition = &code_partition; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; + label = "LED"; + }; + }; + + aliases { + led0 = &led0; + }; +}; + +&flash0 { + reg = <0x10000000 DT_SIZE_M(2)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + settings: partition@0 { + label = "settings"; + reg = <0x00000000 0x100>; + read-only; + }; + + /* + * Usable flash. Starts at 0x100, after the bootloader. The partition + * size is 2MB minus the 0x100 bytes taken by the bootloader. + */ + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (DT_SIZE_M(2) - 0x100)>; + read-only; + }; + }; +}; + +&uart0 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; diff --git a/boards/arm/rpi_pico/rpi_pico.yaml b/boards/arm/rpi_pico/rpi_pico.yaml new file mode 100644 index 0000000000000..0541db609e984 --- /dev/null +++ b/boards/arm/rpi_pico/rpi_pico.yaml @@ -0,0 +1,10 @@ +identifier: rpi_pico +name: RaspberryPi-Pico +type: mcu +arch: arm +flash: 2048 +ram: 264 +toolchain: + - zephyr + - gnuarmemb + - xtools diff --git a/boards/arm/rpi_pico/rpi_pico_defconfig b/boards/arm/rpi_pico/rpi_pico_defconfig new file mode 100644 index 0000000000000..f6f18d9821418 --- /dev/null +++ b/boards/arm/rpi_pico/rpi_pico_defconfig @@ -0,0 +1,8 @@ +CONFIG_SOC_SERIES_RP2XXX=y +CONFIG_SOC_RP2040=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=125000000 +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y +CONFIG_USE_DT_CODE_PARTITION=y From 511660cf6a6d34aaa83c0482469a4a0fd0acd601 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 15 Dec 2021 15:00:06 +0100 Subject: [PATCH 7/8] cmake: Zephyr CMake package module overhaul squash This is a squash of #41301 and is not intended for review in this PR. However, this PR is dependent of the work from #41301. Ignore this commit is this PR. Signed-off-by: Torsten Rasmussen --- cmake/app/boilerplate.cmake | 704 +----------------- cmake/boards.cmake | 40 - cmake/modules/arch.cmake | 40 + cmake/modules/boards.cmake | 147 ++++ cmake/modules/build_configuration.cmake | 112 +++ cmake/{ => modules}/ccache.cmake | 2 + cmake/modules/doc.cmake | 24 + cmake/{ => modules}/dts.cmake | 8 + cmake/{ => modules}/extensions.cmake | 84 +-- cmake/{ => modules}/generic_toolchain.cmake | 10 + cmake/{ => modules}/git.cmake | 1 + cmake/{ => modules}/host-tools.cmake | 2 + cmake/{ => modules}/kconfig.cmake | 18 + cmake/modules/kernel.cmake | 243 ++++++ cmake/{ => modules}/python.cmake | 2 + cmake/modules/root.cmake | 38 + cmake/modules/shields.cmake | 143 ++++ cmake/modules/soc.cmake | 68 ++ cmake/{ => modules}/target_toolchain.cmake | 8 +- .../modules}/unittest.cmake | 0 cmake/modules/user_cache.cmake | 96 +++ cmake/{ => modules}/verify-toolchain.cmake | 2 + cmake/{ => modules}/version.cmake | 5 + cmake/{ => modules}/west.cmake | 5 + cmake/modules/zephyr_default.cmake | 87 +++ cmake/{ => modules}/zephyr_module.cmake | 47 +- cmake/shields.cmake | 18 - cmake/usage/CMakeLists.txt | 10 - doc/CMakeLists.txt | 13 +- scripts/pylib/twister/twisterlib.py | 2 +- share/zephyr-package/cmake/ZephyrConfig.cmake | 39 +- .../cmake/ZephyrConfigVersion.cmake | 4 +- 32 files changed, 1149 insertions(+), 873 deletions(-) delete mode 100644 cmake/boards.cmake create mode 100644 cmake/modules/arch.cmake create mode 100644 cmake/modules/boards.cmake create mode 100644 cmake/modules/build_configuration.cmake rename cmake/{ => modules}/ccache.cmake (94%) create mode 100644 cmake/modules/doc.cmake rename cmake/{ => modules}/dts.cmake (98%) rename cmake/{ => modules}/extensions.cmake (98%) rename cmake/{ => modules}/generic_toolchain.cmake (89%) rename cmake/{ => modules}/git.cmake (97%) rename cmake/{ => modules}/host-tools.cmake (98%) rename cmake/{ => modules}/kconfig.cmake (93%) create mode 100644 cmake/modules/kernel.cmake rename cmake/{ => modules}/python.cmake (98%) create mode 100644 cmake/modules/root.cmake create mode 100644 cmake/modules/shields.cmake create mode 100644 cmake/modules/soc.cmake rename cmake/{ => modules}/target_toolchain.cmake (92%) rename {subsys/testsuite => cmake/modules}/unittest.cmake (100%) create mode 100644 cmake/modules/user_cache.cmake rename cmake/{ => modules}/verify-toolchain.cmake (99%) rename cmake/{ => modules}/version.cmake (90%) rename cmake/{ => modules}/west.cmake (98%) create mode 100644 cmake/modules/zephyr_default.cmake rename cmake/{ => modules}/zephyr_module.cmake (77%) delete mode 100644 cmake/shields.cmake diff --git a/cmake/app/boilerplate.cmake b/cmake/app/boilerplate.cmake index 6102d739c9f51..72aba79600a4b 100644 --- a/cmake/app/boilerplate.cmake +++ b/cmake/app/boilerplate.cmake @@ -1,12 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 -# This file must be included into the toplevel CMakeLists.txt file of -# Zephyr applications. -# Zephyr CMake package automatically includes this file when CMake function -# find_package() is used. -# -# To ensure this file is loaded in a Zephyr application it must start with -# one of those lines: +###################################### +# The use of this file is deprecated # +###################################### + +# To build a Zephyr application it must start with one of those lines: # # find_package(Zephyr) # find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) @@ -14,693 +12,9 @@ # The `REQUIRED HINTS $ENV{ZEPHYR_BASE}` variant is required for any application # inside the Zephyr repository. # -# It exists to reduce boilerplate code that Zephyr expects to be in -# application CMakeLists.txt code. - -# CMake version 3.20 is the real minimum supported version. -# -# Unfortunately CMake requires the toplevel CMakeLists.txt file to -# define the required version, not even invoking it from an included -# file, like boilerplate.cmake, is sufficient. It is however permitted -# to have multiple invocations of cmake_minimum_required. -# -# Under these restraints we use a second 'cmake_minimum_required' -# invocation in every toplevel CMakeLists.txt. -cmake_minimum_required(VERSION 3.20.0) - -define_property(GLOBAL PROPERTY ZEPHYR_LIBS - BRIEF_DOCS "Global list of all Zephyr CMake libs that should be linked in" - FULL_DOCS "Global list of all Zephyr CMake libs that should be linked in. -zephyr_library() appends libs to this list.") -set_property(GLOBAL PROPERTY ZEPHYR_LIBS "") - -define_property(GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS - BRIEF_DOCS "Global list of all Zephyr interface libs that should be linked in." - FULL_DOCS "Global list of all Zephyr interface libs that should be linked in. -zephyr_interface_library_named() appends libs to this list.") -set_property(GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS "") - -define_property(GLOBAL PROPERTY GENERATED_APP_SOURCE_FILES - BRIEF_DOCS "Source files that are generated after Zephyr has been linked once." - FULL_DOCS "\ -Source files that are generated after Zephyr has been linked once.\ -May include dev_handles.c etc." - ) -set_property(GLOBAL PROPERTY GENERATED_APP_SOURCE_FILES "") - -define_property(GLOBAL PROPERTY GENERATED_KERNEL_OBJECT_FILES - BRIEF_DOCS "Object files that are generated after symbol addresses are fixed." - FULL_DOCS "\ -Object files that are generated after symbol addresses are fixed.\ -May include mmu tables, etc." - ) -set_property(GLOBAL PROPERTY GENERATED_KERNEL_OBJECT_FILES "") - -define_property(GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES - BRIEF_DOCS "Source files that are generated after symbol addresses are fixed." - FULL_DOCS "\ -Source files that are generated after symbol addresses are fixed.\ -May include isr_tables.c etc." - ) -set_property(GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES "") - -set(APPLICATION_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Application Source Directory") -set(APPLICATION_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Application Binary Directory") - -set(__build_dir ${CMAKE_CURRENT_BINARY_DIR}/zephyr) - -set(PROJECT_BINARY_DIR ${__build_dir}) - -message(STATUS "Application: ${APPLICATION_SOURCE_DIR}") - -add_custom_target(code_data_relocation_target) - -# The zephyr/runners.yaml file in the build directory is used to -# configure the scripts/west_commands/runners Python package used -# by 'west flash', 'west debug', etc. -# -# This is a helper target for setting property:value pairs related to -# this file: -# -# Property Description -# -------------- -------------------------------------------------- -# bin_file "zephyr.bin" file for flashing -# hex_file "zephyr.hex" file for flashing -# elf_file "zephyr.elf" file for flashing or debugging -# yaml_contents generated contents of runners.yaml -# -# Note: there are quotes around "zephyr.bin" etc. because the actual -# paths can be changed, e.g. to flash signed versions of these files -# for consumption by bootloaders such as MCUboot. -# -# See cmake/flash/CMakeLists.txt for more details. -add_custom_target(runners_yaml_props_target) - -# CMake's 'project' concept has proven to not be very useful for Zephyr -# due in part to how Zephyr is organized and in part to it not fitting well -# with cross compilation. -# Zephyr therefore tries to rely as little as possible on project() -# and its associated variables, e.g. PROJECT_SOURCE_DIR. -# It is recommended to always use ZEPHYR_BASE instead of PROJECT_SOURCE_DIR -# when trying to reference ENV${ZEPHYR_BASE}. - -set(ENV_ZEPHYR_BASE $ENV{ZEPHYR_BASE}) -# This add support for old style boilerplate include. -if((NOT DEFINED ZEPHYR_BASE) AND (DEFINED ENV_ZEPHYR_BASE)) - set(ZEPHYR_BASE ${ENV_ZEPHYR_BASE} CACHE PATH "Zephyr base") -endif() - -find_package(ZephyrBuildConfiguration - QUIET NO_POLICY_SCOPE - NAMES ZephyrBuild - PATHS ${ZEPHYR_BASE}/../* - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_PACKAGE_REGISTRY - NO_CMAKE_SYSTEM_PATH - NO_CMAKE_SYSTEM_PACKAGE_REGISTRY +# Loading of this file directly is deprecated and only kept for backward compatibility. +message(WARNING "Loading of Zephyr boilerplate.cmake directly is deprecated, " + "please use 'find_package(Zephyr)'" ) -# Note any later project() resets PROJECT_SOURCE_DIR -file(TO_CMAKE_PATH "${ZEPHYR_BASE}" PROJECT_SOURCE_DIR) - -set(ZEPHYR_BINARY_DIR ${PROJECT_BINARY_DIR}) - -set(AUTOCONF_H ${__build_dir}/include/generated/autoconf.h) -# Re-configure (Re-execute all CMakeLists.txt code) when autoconf.h changes -set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${AUTOCONF_H}) - - -# -# Import more CMake functions and macros -# - -include(CheckCCompilerFlag) -include(CheckCXXCompilerFlag) -include(${ZEPHYR_BASE}/cmake/extensions.cmake) -include(${ZEPHYR_BASE}/cmake/git.cmake) -include(${ZEPHYR_BASE}/cmake/version.cmake) # depends on hex.cmake - -# -# Find tools -# - -include(${ZEPHYR_BASE}/cmake/python.cmake) -include(${ZEPHYR_BASE}/cmake/west.cmake) -include(${ZEPHYR_BASE}/cmake/ccache.cmake) - -if(ZEPHYR_EXTRA_MODULES) - # ZEPHYR_EXTRA_MODULES has either been specified on the cmake CLI or is - # already in the CMakeCache.txt. This has precedence over the environment - # variable ZEPHYR_EXTRA_MODULES -elseif(DEFINED ENV{ZEPHYR_EXTRA_MODULES}) - set(ZEPHYR_EXTRA_MODULES $ENV{ZEPHYR_EXTRA_MODULES}) -endif() - -# 'MODULE_EXT_ROOT' is a prioritized list of directories where module glue code -# may be found. It always includes ${ZEPHYR_BASE} at the lowest priority. -# For module roots, later entries may overrule module settings already defined -# by processed module roots, hence first in list means lowest priority. -zephyr_file(APPLICATION_ROOT MODULE_EXT_ROOT) -list(INSERT MODULE_EXT_ROOT 0 ${ZEPHYR_BASE}) - -# -# Find Zephyr modules. -# Those may contain additional DTS, BOARD, SOC, ARCH ROOTs. -# Also create the Kconfig binary dir for generated Kconf files. -# -set(KCONFIG_BINARY_DIR ${CMAKE_BINARY_DIR}/Kconfig) -file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}) -include(${ZEPHYR_BASE}/cmake/zephyr_module.cmake) - -if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) - message(FATAL_ERROR "Source directory equals build directory.\ - In-source builds are not supported.\ - Please specify a build directory, e.g. cmake -Bbuild -H.") -endif() - -add_custom_target( - pristine - COMMAND ${CMAKE_COMMAND} -DBINARY_DIR=${APPLICATION_BINARY_DIR} - -DSOURCE_DIR=${APPLICATION_SOURCE_DIR} - -P ${ZEPHYR_BASE}/cmake/pristine.cmake - # Equivalent to rm -rf build/* - ) - -# Dummy add to generate files. -zephyr_linker_sources(SECTIONS) - -# 'BOARD_ROOT' is a prioritized list of directories where boards may -# be found. It always includes ${ZEPHYR_BASE} at the lowest priority. -zephyr_file(APPLICATION_ROOT BOARD_ROOT) -list(APPEND BOARD_ROOT ${ZEPHYR_BASE}) - -# 'SOC_ROOT' is a prioritized list of directories where socs may be -# found. It always includes ${ZEPHYR_BASE}/soc at the lowest priority. -zephyr_file(APPLICATION_ROOT SOC_ROOT) -list(APPEND SOC_ROOT ${ZEPHYR_BASE}) - -# 'ARCH_ROOT' is a prioritized list of directories where archs may be -# found. It always includes ${ZEPHYR_BASE} at the lowest priority. -zephyr_file(APPLICATION_ROOT ARCH_ROOT) -list(APPEND ARCH_ROOT ${ZEPHYR_BASE}) - -# Check that BOARD has been provided, and that it has not changed. -zephyr_check_cache(BOARD REQUIRED) - -string(FIND "${BOARD}" "@" REVISION_SEPARATOR_INDEX) -if(NOT (REVISION_SEPARATOR_INDEX EQUAL -1)) - math(EXPR BOARD_REVISION_INDEX "${REVISION_SEPARATOR_INDEX} + 1") - string(SUBSTRING ${BOARD} ${BOARD_REVISION_INDEX} -1 BOARD_REVISION) - string(SUBSTRING ${BOARD} 0 ${REVISION_SEPARATOR_INDEX} BOARD) -endif() - -set(BOARD_MESSAGE "Board: ${BOARD}") - -if(DEFINED ENV{ZEPHYR_BOARD_ALIASES}) - include($ENV{ZEPHYR_BOARD_ALIASES}) - if(${BOARD}_BOARD_ALIAS) - set(BOARD_ALIAS ${BOARD} CACHE STRING "Board alias, provided by user") - set(BOARD ${${BOARD}_BOARD_ALIAS}) - message(STATUS "Aliased BOARD=${BOARD_ALIAS} changed to ${BOARD}") - endif() -endif() -include(${ZEPHYR_BASE}/boards/deprecated.cmake) -if(${BOARD}_DEPRECATED) - set(BOARD_DEPRECATED ${BOARD} CACHE STRING "Deprecated board name, provided by user") - set(BOARD ${${BOARD}_DEPRECATED}) - message(WARNING "Deprecated BOARD=${BOARD_DEPRECATED} name specified, board automatically changed to: ${BOARD}.") -endif() - -zephyr_boilerplate_watch(BOARD) - -foreach(root ${BOARD_ROOT}) - # Check that the board root looks reasonable. - if(NOT IS_DIRECTORY "${root}/boards") - message(WARNING "BOARD_ROOT element without a 'boards' subdirectory: -${root} -Hints: - - if your board directory is '/foo/bar/boards//my_board' then add '/foo/bar' to BOARD_ROOT, not the entire board directory - - if in doubt, use absolute paths") - endif() - - # NB: find_path will return immediately if the output variable is - # already set - if (BOARD_ALIAS) - find_path(BOARD_HIDDEN_DIR - NAMES ${BOARD_ALIAS}_defconfig - PATHS ${root}/boards/*/* - NO_DEFAULT_PATH - ) - if(BOARD_HIDDEN_DIR) - message("Board alias ${BOARD_ALIAS} is hiding the real board of same name") - endif() - endif() - find_path(BOARD_DIR - NAMES ${BOARD}_defconfig - PATHS ${root}/boards/*/* - NO_DEFAULT_PATH - ) - if(BOARD_DIR AND NOT (${root} STREQUAL ${ZEPHYR_BASE})) - set(USING_OUT_OF_TREE_BOARD 1) - endif() -endforeach() - -if(EXISTS ${BOARD_DIR}/revision.cmake) - # Board provides revision handling. - include(${BOARD_DIR}/revision.cmake) -elseif(BOARD_REVISION) - message(WARNING "Board revision ${BOARD_REVISION} specified for ${BOARD}, \ - but board has no revision so revision will be ignored.") -endif() - -if(DEFINED BOARD_REVISION) - set(BOARD_MESSAGE "${BOARD_MESSAGE}, Revision: ${BOARD_REVISION}") - if(DEFINED ACTIVE_BOARD_REVISION) - set(BOARD_MESSAGE "${BOARD_MESSAGE} (Active: ${ACTIVE_BOARD_REVISION})") - set(BOARD_REVISION ${ACTIVE_BOARD_REVISION}) - endif() - - string(REPLACE "." "_" BOARD_REVISION_STRING ${BOARD_REVISION}) -endif() - -# Check that SHIELD has not changed. -zephyr_check_cache(SHIELD WATCH) - -if(SHIELD) - set(BOARD_MESSAGE "${BOARD_MESSAGE}, Shield(s): ${SHIELD}") -endif() - -message(STATUS "${BOARD_MESSAGE}") - -if(DEFINED SHIELD) - string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}") -endif() -# SHIELD-NOTFOUND is a real CMake list, from which valid shields can be popped. -# After processing all shields, only invalid shields will be left in this list. -set(SHIELD-NOTFOUND ${SHIELD_AS_LIST}) - -# Use BOARD to search for a '_defconfig' file. -# e.g. zephyr/boards/arm/96b_carbon_nrf51/96b_carbon_nrf51_defconfig. -# When found, use that path to infer the ARCH we are building for. -foreach(root ${BOARD_ROOT}) - set(shield_dir ${root}/boards/shields) - # Match the Kconfig.shield files in the shield directories to make sure we are - # finding shields, e.g. x_nucleo_iks01a1/Kconfig.shield - file(GLOB_RECURSE shields_refs_list ${shield_dir}/*/Kconfig.shield) - - # The above gives a list like - # x_nucleo_iks01a1/Kconfig.shield;x_nucleo_iks01a2/Kconfig.shield - # we construct a list of shield names by extracting the folder and find - # and overlay files in there. Each overlay corresponds to a shield. - # We obtain the shield name by removing the overlay extension. - unset(SHIELD_LIST) - foreach(shields_refs ${shields_refs_list}) - get_filename_component(shield_path ${shields_refs} DIRECTORY) - file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay) - foreach(overlay ${shield_overlays}) - get_filename_component(shield ${overlay} NAME_WE) - list(APPEND SHIELD_LIST ${shield}) - set(SHIELD_DIR_${shield} ${shield_path}) - endforeach() - endforeach() - - if(DEFINED SHIELD) - foreach(s ${SHIELD_AS_LIST}) - if(NOT ${s} IN_LIST SHIELD_LIST) - continue() - endif() - - list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) - - # if shield config flag is on, add shield overlay to the shield overlays - # list and dts_fixup file to the shield fixup file - list(APPEND - shield_dts_files - ${SHIELD_DIR_${s}}/${s}.overlay - ) - - list(APPEND - shield_dts_fixups - ${SHIELD_DIR_${s}}/dts_fixup.h - ) - - list(APPEND - SHIELD_DIRS - ${SHIELD_DIR_${s}} - ) - - # search for shield/shield.conf file - if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) - # add shield.conf to the shield config list - list(APPEND - shield_conf_files - ${SHIELD_DIR_${s}}/${s}.conf - ) - endif() - - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards - DTS shield_dts_files - KCONF shield_conf_files - ) - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} - DTS shield_dts_files - KCONF shield_conf_files - ) - endforeach() - endif() -endforeach() - -if(NOT BOARD_DIR) - message("No board named '${BOARD}' found. - -Please choose one of the following boards: -") - execute_process( - COMMAND - ${CMAKE_COMMAND} - -DZEPHYR_BASE=${ZEPHYR_BASE} - -DBOARD_ROOT=${BOARD_ROOT} - -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} - -P ${ZEPHYR_BASE}/cmake/boards.cmake - ) - unset(CACHED_BOARD CACHE) - message(FATAL_ERROR "Invalid BOARD; see above.") -endif() - -if(DEFINED SHIELD AND NOT (SHIELD-NOTFOUND STREQUAL "")) - foreach (s ${SHIELD-NOTFOUND}) - message("No shield named '${s}' found") - endforeach() - message("Please choose from among the following shields:") - string(REPLACE ";" "\\;" SHIELD_LIST_ESCAPED "${SHIELD_LIST}") - execute_process( - COMMAND - ${CMAKE_COMMAND} - -DZEPHYR_BASE=${ZEPHYR_BASE} - -DSHIELD_LIST=${SHIELD_LIST_ESCAPED} - -P ${ZEPHYR_BASE}/cmake/shields.cmake - ) - unset(CACHED_SHIELD CACHE) - message(FATAL_ERROR "Invalid SHIELD; see above.") -endif() - -get_filename_component(BOARD_ARCH_DIR ${BOARD_DIR} DIRECTORY) -get_filename_component(ARCH ${BOARD_ARCH_DIR} NAME) - -foreach(root ${ARCH_ROOT}) - if(EXISTS ${root}/arch/${ARCH}/CMakeLists.txt) - set(ARCH_DIR ${root}/arch) - break() - endif() -endforeach() - -if(NOT ARCH_DIR) - message(FATAL_ERROR "Could not find ARCH=${ARCH} for BOARD=${BOARD}, \ -please check your installation. ARCH roots searched: \n\ -${ARCH_ROOT}") -endif() - -if(DEFINED APPLICATION_CONFIG_DIR) - string(CONFIGURE ${APPLICATION_CONFIG_DIR} APPLICATION_CONFIG_DIR) - if(NOT IS_ABSOLUTE ${APPLICATION_CONFIG_DIR}) - get_filename_component(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} ABSOLUTE) - endif() -else() - # Application config dir is not set, so we default to the application - # source directory as configuration directory. - set(APPLICATION_CONFIG_DIR ${APPLICATION_SOURCE_DIR}) -endif() - -if(DEFINED CONF_FILE) - # This ensures that CACHE{CONF_FILE} will be set correctly to current scope - # variable CONF_FILE. An already current scope variable will stay the same. - set(CONF_FILE ${CONF_FILE}) - - # CONF_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. This has precedence over the environment - # variable CONF_FILE and the default prj.conf - - # In order to support a `prj_.conf pattern for auto inclusion of board - # overlays, then we must first ensure only a single conf file is provided. - string(REPLACE " " ";" CONF_FILE_AS_LIST "${CONF_FILE}") - list(LENGTH CONF_FILE_AS_LIST CONF_FILE_LENGTH) - if(${CONF_FILE_LENGTH} EQUAL 1) - # Need the file name to look for match. - # Need path in order to check if it is absolute. - get_filename_component(CONF_FILE_NAME ${CONF_FILE} NAME) - if(${CONF_FILE_NAME} MATCHES "prj_(.*).conf") - set(CONF_FILE_BUILD_TYPE ${CMAKE_MATCH_1}) - set(CONF_FILE_INCLUDE_FRAGMENTS true) - endif() - endif() -elseif(CACHED_CONF_FILE) - # Cached conf file is present. - # That value has precedence over anything else than a new - # `cmake -DCONF_FILE=` invocation. - set(CONF_FILE ${CACHED_CONF_FILE}) -elseif(DEFINED ENV{CONF_FILE}) - set(CONF_FILE $ENV{CONF_FILE}) - -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) - set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) - -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj.conf) - set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj.conf) - set(CONF_FILE_INCLUDE_FRAGMENTS true) -endif() - -if(CONF_FILE_INCLUDE_FRAGMENTS) - zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE BUILD ${CONF_FILE_BUILD_TYPE}) -endif() - -set(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} CACHE INTERNAL "The application configuration folder") -set(CACHED_CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ -the configuration settings specified in an alternate .conf file using this parameter. \ -These settings will override the settings in the application’s .config file or its default .conf file.\ -Multiple files may be listed, e.g. CONF_FILE=\"prj1.confi;prj2.conf\" \ -The CACHED_CONF_FILE is internal Zephyr variable used between CMake runs. \ -To change CONF_FILE, use the CONF_FILE variable.") -unset(CONF_FILE CACHE) - -zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS) - -# The CONF_FILE variable is now set to its final value. -zephyr_boilerplate_watch(CONF_FILE) - -if(DTC_OVERLAY_FILE) - # DTC_OVERLAY_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. -elseif(APP_BOARD_DTS) - set(DTC_OVERLAY_FILE ${APP_BOARD_DTS}) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/app.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/app.overlay) -endif() - -set(DTC_OVERLAY_FILE ${DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ -build the application using the DT configuration settings specified in an \ -alternate .overlay file using this parameter. These settings will override the \ -settings in the board's .dts file. Multiple files may be listed, e.g. \ -DTC_OVERLAY_FILE=\"dts1.overlay dts2.overlay\"") - -# Populate USER_CACHE_DIR with a directory that user applications may -# write cache files to. -if(NOT DEFINED USER_CACHE_DIR) - find_appropriate_cache_directory(USER_CACHE_DIR) -endif() -message(STATUS "Cache files will be written to: ${USER_CACHE_DIR}") - -# Prevent CMake from testing the toolchain -set(CMAKE_C_COMPILER_FORCED 1) -set(CMAKE_CXX_COMPILER_FORCED 1) - -include(${ZEPHYR_BASE}/cmake/verify-toolchain.cmake) -include(${ZEPHYR_BASE}/cmake/host-tools.cmake) - -# Include board specific device-tree flags before parsing. -include(${BOARD_DIR}/pre_dt_board.cmake OPTIONAL) - -# The DTC_OVERLAY_FILE variable is now set to its final value. -zephyr_boilerplate_watch(DTC_OVERLAY_FILE) - -# DTS should be close to kconfig because CONFIG_ variables from -# kconfig and dts should be available at the same time. -# -# The DT system uses a C preprocessor for it's code generation needs. -# This creates an awkward chicken-and-egg problem, because we don't -# always know exactly which toolchain the user needs until we know -# more about the target, e.g. after DT and Kconfig. -# -# To resolve this we find "some" C toolchain, configure it generically -# with the minimal amount of configuration needed to have it -# preprocess DT sources, and then, after we have finished processing -# both DT and Kconfig we complete the target-specific configuration, -# and possibly change the toolchain. -include(${ZEPHYR_BASE}/cmake/generic_toolchain.cmake) -include(${ZEPHYR_BASE}/cmake/dts.cmake) -include(${ZEPHYR_BASE}/cmake/kconfig.cmake) - -set(SOC_NAME ${CONFIG_SOC}) -set(SOC_SERIES ${CONFIG_SOC_SERIES}) -set(SOC_TOOLCHAIN_NAME ${CONFIG_SOC_TOOLCHAIN_NAME}) -set(SOC_FAMILY ${CONFIG_SOC_FAMILY}) - -# For the gen_app_partitions.py to work correctly, we must ensure that -# all targets exports their compile commands to fetch object files. -# We enable it unconditionally, as this is also useful for several IDEs -set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE CACHE BOOL - "Export CMake compile commands. Used by gen_app_partitions.py script" - FORCE -) - -if("${SOC_SERIES}" STREQUAL "") - set(SOC_PATH ${SOC_NAME}) -else() - set(SOC_PATH ${SOC_FAMILY}/${SOC_SERIES}) -endif() - -# Use SOC to search for a 'CMakeLists.txt' file. -# e.g. zephyr/soc/xtense/intel_apl_adsp/CMakeLists.txt. -foreach(root ${SOC_ROOT}) - # Check that the root looks reasonable. - if(NOT IS_DIRECTORY "${root}/soc") - message(WARNING "SOC_ROOT element without a 'soc' subdirectory: -${root} -Hints: - - if your SoC family directory is '/foo/bar/soc//my_soc_family', then add '/foo/bar' to SOC_ROOT, not the entire SoC family path - - if in doubt, use absolute paths") - endif() - - if(EXISTS ${root}/soc/${ARCH}/${SOC_PATH}) - set(SOC_DIR ${root}/soc) - break() - endif() -endforeach() - -if(NOT SOC_DIR) - message(FATAL_ERROR "Could not find SOC=${SOC_NAME} for BOARD=${BOARD}, \ -please check your installation. SOC roots searched: \n\ -${SOC_ROOT}") -endif() - -include(${ZEPHYR_BASE}/cmake/target_toolchain.cmake) - -project(Zephyr-Kernel VERSION ${PROJECT_VERSION}) - -# Add .S file extension suffix into CMAKE_ASM_SOURCE_FILE_EXTENSIONS, -# because clang from OneApi can't recongnize them as asm files on -# windows now. -list(APPEND CMAKE_ASM_SOURCE_FILE_EXTENSIONS "S") -enable_language(C CXX ASM) - -# The setup / configuration of the toolchain itself and the configuration of -# supported compilation flags are now split, as this allows to use the toolchain -# for generic purposes, for example DTS, and then test the toolchain for -# supported flags at stage two. -# Testing the toolchain flags requires the enable_language() to have been called in CMake. - -# Verify that the toolchain can compile a dummy file, if it is not we -# won't be able to test for compatibility with certain C flags. -zephyr_check_compiler_flag(C "" toolchain_is_ok) -assert(toolchain_is_ok "The toolchain is unable to build a dummy C file. See CMakeError.log.") - -include(${ZEPHYR_BASE}/cmake/target_toolchain_flags.cmake) - -# 'project' sets PROJECT_BINARY_DIR to ${CMAKE_CURRENT_BINARY_DIR}, -# but for legacy reasons we need it to be set to -# ${CMAKE_CURRENT_BINARY_DIR}/zephyr -set(PROJECT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/zephyr) -set(PROJECT_SOURCE_DIR ${ZEPHYR_BASE}) - -set(KERNEL_NAME ${CONFIG_KERNEL_BIN_NAME}) - -set(KERNEL_ELF_NAME ${KERNEL_NAME}.elf) -set(KERNEL_BIN_NAME ${KERNEL_NAME}.bin) -set(KERNEL_HEX_NAME ${KERNEL_NAME}.hex) -set(KERNEL_UF2_NAME ${KERNEL_NAME}.uf2) -set(KERNEL_MAP_NAME ${KERNEL_NAME}.map) -set(KERNEL_LST_NAME ${KERNEL_NAME}.lst) -set(KERNEL_S19_NAME ${KERNEL_NAME}.s19) -set(KERNEL_EXE_NAME ${KERNEL_NAME}.exe) -set(KERNEL_STAT_NAME ${KERNEL_NAME}.stat) -set(KERNEL_STRIP_NAME ${KERNEL_NAME}.strip) -set(KERNEL_META_NAME ${KERNEL_NAME}.meta) - -include(${BOARD_DIR}/board.cmake OPTIONAL) - -# If we are using a suitable ethernet driver inside qemu, then these options -# must be set, otherwise a zephyr instance cannot receive any network packets. -# The Qemu supported ethernet driver should define CONFIG_ETH_NIC_MODEL -# string that tells what nic model Qemu should use. -if(CONFIG_QEMU_TARGET) - if ((CONFIG_NET_QEMU_ETHERNET OR CONFIG_NET_QEMU_USER) AND NOT CONFIG_ETH_NIC_MODEL) - message(FATAL_ERROR " - No Qemu ethernet driver configured! - Enable Qemu supported ethernet driver like e1000 at drivers/ethernet" - ) - elseif(CONFIG_NET_QEMU_ETHERNET) - if(CONFIG_ETH_QEMU_EXTRA_ARGS) - set(NET_QEMU_ETH_EXTRA_ARGS ",${CONFIG_ETH_QEMU_EXTRA_ARGS}") - endif() - list(APPEND QEMU_FLAGS_${ARCH} - -nic tap,model=${CONFIG_ETH_NIC_MODEL},script=no,downscript=no,ifname=${CONFIG_ETH_QEMU_IFACE_NAME}${NET_QEMU_ETH_EXTRA_ARGS} - ) - elseif(CONFIG_NET_QEMU_USER) - list(APPEND QEMU_FLAGS_${ARCH} - -nic user,model=${CONFIG_ETH_NIC_MODEL},${CONFIG_NET_QEMU_USER_EXTRA_ARGS} - ) - else() - list(APPEND QEMU_FLAGS_${ARCH} - -net none - ) - endif() -endif() - -# General purpose Zephyr target. -# This target can be used for custom zephyr settings that needs to be used elsewhere in the build system -# -# Currently used properties: -# - COMPILES_OPTIONS: Used by application memory partition feature -add_custom_target(zephyr_property_target) - -# "app" is a CMake library containing all the application code and is -# modified by the entry point ${APPLICATION_SOURCE_DIR}/CMakeLists.txt -# that was specified when cmake was called. -zephyr_library_named(app) -set_property(TARGET app PROPERTY ARCHIVE_OUTPUT_DIRECTORY app) - -add_subdirectory(${ZEPHYR_BASE} ${__build_dir}) - -# Link 'app' with the Zephyr interface libraries. -# -# NB: This must be done in boilerplate.cmake because 'app' can only be -# modified in the CMakeLists.txt file that created it. And it must be -# done after 'add_subdirectory(${ZEPHYR_BASE} ${__build_dir})' -# because interface libraries are defined while processing that -# subdirectory. -get_property(ZEPHYR_INTERFACE_LIBS_PROPERTY GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS) -foreach(boilerplate_lib ${ZEPHYR_INTERFACE_LIBS_PROPERTY}) - # Linking 'app' with 'boilerplate_lib' causes 'app' to inherit the INTERFACE - # properties of 'boilerplate_lib'. The most common property is 'include - # directories', but it is also possible to have defines and compiler - # flags in the interface of a library. - # - string(TOUPPER ${boilerplate_lib} boilerplate_lib_upper_case) # Support lowercase lib names - target_link_libraries_ifdef( - CONFIG_APP_LINK_WITH_${boilerplate_lib_upper_case} - app - PUBLIC - ${boilerplate_lib} - ) -endforeach() - -if("${CMAKE_EXTRA_GENERATOR}" STREQUAL "Eclipse CDT4") - # Call the amendment function before .project and .cproject generation - # C and CXX includes, defines in .cproject without __cplusplus - # with project includes and defines - include(${ZEPHYR_BASE}/cmake/ide/eclipse_cdt4_generator_amendment.cmake) - eclipse_cdt4_generator_amendment(1) -endif() +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) diff --git a/cmake/boards.cmake b/cmake/boards.cmake deleted file mode 100644 index 16216c4f2a50a..0000000000000 --- a/cmake/boards.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -set(arch_root_args) -foreach(root ${ARCH_ROOT}) - list(APPEND arch_root_args "--arch-root=${root}") -endforeach() - -set(board_root_args) -foreach(root ${BOARD_ROOT}) - list(APPEND board_root_args "--board-root=${root}") -endforeach() - -set(list_boards_commands - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/list_boards.py - ${arch_root_args} ${board_root_args} -) - -if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE) -# If this file is invoked as a script directly with -P: -# cmake [options] -P board.cmake -# Note that CMAKE_PARENT_LIST_FILE not being set ensures that this present -# file is being invoked directly with -P, and not via an include directive from -# some other script - -# The options available are: -# ARCH_ROOT: Semi-colon separated arch roots -# BOARD_ROOT: Semi-colon separated board roots -# FILE_OUT: Set to a file path to save the boards to a file. If not defined the -# the contents will be printed to stdout -cmake_minimum_required(VERSION 3.20.0) - -set(NO_BOILERPLATE TRUE) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) - -if (FILE_OUT) - list(APPEND list_boards_commands OUTPUT_FILE "${FILE_OUT}") -endif() - -execute_process(${list_boards_commands}) -endif() diff --git a/cmake/modules/arch.cmake b/cmake/modules/arch.cmake new file mode 100644 index 0000000000000..2f949287e8056 --- /dev/null +++ b/cmake/modules/arch.cmake @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2022, Nordic Semiconductor ASA + +# Configure ARCH settings based on board directory and arch root. +# +# This CMake module will set the following variables in the build system based +# on board directory and arch root. +# +# If no implementation is available for the current arch an error will be raised. +# +# Outcome: +# The following variables will be defined when this CMake module completes: +# +# - ARCH: Name of the arch in use. +# - ARCH_DIR: Directory containing the arch implementation. +# +# Variable dependencies: +# - ARCH_ROOT: CMake list of arch roots containing arch implementations +# - BOARD_DIR: CMake variable specifying the directory of the selected BOARD + +# 'ARCH_ROOT' is a prioritized list of directories where archs may be +# found. It always includes ${ZEPHYR_BASE} at the lowest priority. +list(APPEND ARCH_ROOT ${ZEPHYR_BASE}) + +cmake_path(GET BOARD_DIR PARENT_PATH board_arch_dir) +cmake_path(GET board_arch_dir FILENAME ARCH) + +foreach(root ${ARCH_ROOT}) + if(EXISTS ${root}/arch/${ARCH}/CMakeLists.txt) + set(ARCH_DIR ${root}/arch) + break() + endif() +endforeach() + +if(NOT ARCH_DIR) + message(FATAL_ERROR "Could not find ARCH=${ARCH} for BOARD=${BOARD}, \ +please check your installation. ARCH roots searched: \n\ +${ARCH_ROOT}") +endif() diff --git a/cmake/modules/boards.cmake b/cmake/modules/boards.cmake new file mode 100644 index 0000000000000..dfcc3c83ef693 --- /dev/null +++ b/cmake/modules/boards.cmake @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Validate board and setup boards target. +# +# This CMake module will validate the BOARD argument as well as splitting the +# BOARD argument into and . +# +# If a board implementation is not found for the specified board an error will +# be raised and list of valid boards will be printed. +# +# If user provided board is a board alias, the board will be adjusted to real +# board name. +# +# If board name is deprecated, then board will be adjusted to new board name and +# a deprecation warning will be printed to the user. +# +# Outcome: +# The following variables will be defined when this CMake module completes: +# +# - BOARD: Board, without revision field. +# - BOARD_REVISION: Board revision +# - BOARD_DIR: Board directory with the implementation for selected board +# - ARCH_DIR: Arch dir for extracted from selected board +# +# The following targets will be defined when this CMake module completes: +# - board : when invoked a list of valid boards will be printed +# +# Variable dependencies: +# - BOARD_ROOT: CMake list of board roots containing board implementations +# - ARCH_ROOT: CMake list of arch roots containing arch implementations +# +# CMake module dependencies: +# - extensions CMake module. + +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) + +# Check that BOARD has been provided, and that it has not changed. +# If user tries to change the BOARD, the BOARD value is reset to the BOARD_CACHED value. +zephyr_check_cache(BOARD REQUIRED) + +# 'BOARD_ROOT' is a prioritized list of directories where boards may +# be found. It always includes ${ZEPHYR_BASE} at the lowest priority. +list(APPEND BOARD_ROOT ${ZEPHYR_BASE}) + +string(FIND "${BOARD}" "@" REVISION_SEPARATOR_INDEX) +if(NOT (REVISION_SEPARATOR_INDEX EQUAL -1)) + math(EXPR BOARD_REVISION_INDEX "${REVISION_SEPARATOR_INDEX} + 1") + string(SUBSTRING ${BOARD} ${BOARD_REVISION_INDEX} -1 BOARD_REVISION) + string(SUBSTRING ${BOARD} 0 ${REVISION_SEPARATOR_INDEX} BOARD) +endif() + +message(STATUS "Board: ${BOARD}") + +if(DEFINED ENV{ZEPHYR_BOARD_ALIASES}) + include($ENV{ZEPHYR_BOARD_ALIASES}) + if(${BOARD}_BOARD_ALIAS) + set(BOARD_ALIAS ${BOARD} CACHE STRING "Board alias, provided by user") + set(BOARD ${${BOARD}_BOARD_ALIAS}) + message(STATUS "Aliased BOARD=${BOARD_ALIAS} changed to ${BOARD}") + endif() +endif() +include(${ZEPHYR_BASE}/boards/deprecated.cmake) +if(${BOARD}_DEPRECATED) + set(BOARD_DEPRECATED ${BOARD} CACHE STRING "Deprecated board name, provided by user") + set(BOARD ${${BOARD}_DEPRECATED}) + message(WARNING "Deprecated BOARD=${BOARD_DEPRECATED} name specified, board automatically changed to: ${BOARD}.") +endif() + +zephyr_boilerplate_watch(BOARD) + +foreach(root ${BOARD_ROOT}) + # Check that the board root looks reasonable. + if(NOT IS_DIRECTORY "${root}/boards") + message(WARNING "BOARD_ROOT element without a 'boards' subdirectory: +${root} +Hints: + - if your board directory is '/foo/bar/boards//my_board' then add '/foo/bar' to BOARD_ROOT, not the entire board directory + - if in doubt, use absolute paths") + endif() + + # NB: find_path will return immediately if the output variable is + # already set + if (BOARD_ALIAS) + find_path(BOARD_HIDDEN_DIR + NAMES ${BOARD_ALIAS}_defconfig + PATHS ${root}/boards/*/* + NO_DEFAULT_PATH + ) + if(BOARD_HIDDEN_DIR) + message("Board alias ${BOARD_ALIAS} is hiding the real board of same name") + endif() + endif() + find_path(BOARD_DIR + NAMES ${BOARD}_defconfig + PATHS ${root}/boards/*/* + NO_DEFAULT_PATH + ) + if(BOARD_DIR AND NOT (${root} STREQUAL ${ZEPHYR_BASE})) + set(USING_OUT_OF_TREE_BOARD 1) + endif() +endforeach() + +if(EXISTS ${BOARD_DIR}/revision.cmake) + # Board provides revision handling. + include(${BOARD_DIR}/revision.cmake) +elseif(BOARD_REVISION) + message(WARNING "Board revision ${BOARD_REVISION} specified for ${BOARD}, \ + but board has no revision so revision will be ignored.") +endif() + +if(DEFINED BOARD_REVISION) + set(BOARD_MESSAGE "${BOARD_MESSAGE}, Revision: ${BOARD_REVISION}") + if(DEFINED ACTIVE_BOARD_REVISION) + set(BOARD_MESSAGE "${BOARD_MESSAGE} (Active: ${ACTIVE_BOARD_REVISION})") + set(BOARD_REVISION ${ACTIVE_BOARD_REVISION}) + endif() + + string(REPLACE "." "_" BOARD_REVISION_STRING ${BOARD_REVISION}) +endif() + +# Prepare boards usage command printing. +# This command prints all boards in the system in the following cases: +# - User specifies an invalid BOARD +# - User invokes ' boards' target +list(TRANSFORM ARCH_ROOT PREPEND "--arch-root=" OUTPUT_VARIABLE arch_root_args) +list(TRANSFORM BOARD_ROOT PREPEND "--board-root=" OUTPUT_VARIABLE board_root_args) + +set(list_boards_commands + COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/list_boards.py + ${arch_root_args} ${board_root_args} +) + +if(NOT BOARD_DIR) + message("No board named '${BOARD}' found.\n\n" + "Please choose one of the following boards:\n" + ) + execute_process(${list_boards_commands}) + unset(CACHED_BOARD CACHE) + message(FATAL_ERROR "Invalid BOARD; see above.") +endif() + +add_custom_target(boards ${list_boards_commands} USES_TERMINAL) diff --git a/cmake/modules/build_configuration.cmake b/cmake/modules/build_configuration.cmake new file mode 100644 index 0000000000000..7e19babb9ea2c --- /dev/null +++ b/cmake/modules/build_configuration.cmake @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Configure Zephyr build system. +# +# This CMake module will setup various configuration settings based on user input. +# +# Outcome: +# The following variables will be defined when this CMake module completes: +# +# - CONF_FILE: List of Kconfig fragments +# - DTC_OVERLAY_FILE: List of devicetree overlay files +# - APPLICATIUON_CONFIG_DIR: Root folder for application configuration +# +# If any of the above variables are already set when this CMake module is +# loaded, then no changes to the variable will happen. +# +# CMake module dependencies: +# - extensions CMake module. + +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) + +if(DEFINED APPLICATION_CONFIG_DIR) + string(CONFIGURE ${APPLICATION_CONFIG_DIR} APPLICATION_CONFIG_DIR) + if(NOT IS_ABSOLUTE ${APPLICATION_CONFIG_DIR}) + get_filename_component(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} ABSOLUTE) + endif() +else() + # Application config dir is not set, so we default to the application + # source directory as configuration directory. + set(APPLICATION_CONFIG_DIR ${APPLICATION_SOURCE_DIR}) +endif() + +if(DEFINED CONF_FILE) + # This ensures that CACHE{CONF_FILE} will be set correctly to current scope + # variable CONF_FILE. An already current scope variable will stay the same. + set(CONF_FILE ${CONF_FILE}) + + # CONF_FILE has either been specified on the cmake CLI or is already + # in the CMakeCache.txt. This has precedence over the environment + # variable CONF_FILE and the default prj.conf + + # In order to support a `prj_.conf pattern for auto inclusion of board + # overlays, then we must first ensure only a single conf file is provided. + string(REPLACE " " ";" CONF_FILE_AS_LIST "${CONF_FILE}") + list(LENGTH CONF_FILE_AS_LIST CONF_FILE_LENGTH) + if(${CONF_FILE_LENGTH} EQUAL 1) + # Need the file name to look for match. + # Need path in order to check if it is absolute. + get_filename_component(CONF_FILE_NAME ${CONF_FILE} NAME) + if(${CONF_FILE_NAME} MATCHES "prj_(.*).conf") + set(CONF_FILE_BUILD_TYPE ${CMAKE_MATCH_1}) + set(CONF_FILE_INCLUDE_FRAGMENTS true) + endif() + endif() +elseif(CACHED_CONF_FILE) + # Cached conf file is present. + # That value has precedence over anything else than a new + # `cmake -DCONF_FILE=` invocation. + set(CONF_FILE ${CACHED_CONF_FILE}) +elseif(DEFINED ENV{CONF_FILE}) + set(CONF_FILE $ENV{CONF_FILE}) + +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) + set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) + +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj.conf) + set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj.conf) + set(CONF_FILE_INCLUDE_FRAGMENTS true) +endif() + +if(CONF_FILE_INCLUDE_FRAGMENTS) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE BUILD ${CONF_FILE_BUILD_TYPE}) +endif() + +set(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} CACHE INTERNAL "The application configuration folder") +set(CACHED_CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ +the configuration settings specified in an alternate .conf file using this parameter. \ +These settings will override the settings in the application’s .config file or its default .conf file.\ +Multiple files may be listed, e.g. CONF_FILE=\"prj1.confi;prj2.conf\" \ +The CACHED_CONF_FILE is internal Zephyr variable used between CMake runs. \ +To change CONF_FILE, use the CONF_FILE variable.") +unset(CONF_FILE CACHE) + +zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS) + +# The CONF_FILE variable is now set to its final value. +zephyr_boilerplate_watch(CONF_FILE) + +if(DTC_OVERLAY_FILE) + # DTC_OVERLAY_FILE has either been specified on the cmake CLI or is already + # in the CMakeCache.txt. +elseif(APP_BOARD_DTS) + set(DTC_OVERLAY_FILE ${APP_BOARD_DTS}) +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) + set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/app.overlay) + set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/app.overlay) +endif() + +set(DTC_OVERLAY_FILE ${DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ +build the application using the DT configuration settings specified in an \ +alternate .overlay file using this parameter. These settings will override the \ +settings in the board's .dts file. Multiple files may be listed, e.g. \ +DTC_OVERLAY_FILE=\"dts1.overlay dts2.overlay\"") + +# The DTC_OVERLAY_FILE variable is now set to its final value. +zephyr_boilerplate_watch(DTC_OVERLAY_FILE) diff --git a/cmake/ccache.cmake b/cmake/modules/ccache.cmake similarity index 94% rename from cmake/ccache.cmake rename to cmake/modules/ccache.cmake index cfe7f91aed74e..c1d41d6b9e44a 100644 --- a/cmake/ccache.cmake +++ b/cmake/modules/ccache.cmake @@ -3,6 +3,8 @@ # Use ccache if it is installed, unless the user explicitly disables # it by setting USE_CCACHE=0. +include_guard(GLOBAL) + if(USE_CCACHE STREQUAL "0") else() find_program(CCACHE_FOUND ccache) diff --git a/cmake/modules/doc.cmake b/cmake/modules/doc.cmake new file mode 100644 index 0000000000000..daf16336405c7 --- /dev/null +++ b/cmake/modules/doc.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# This CMake module will load all Zephyr CMake modules required for a +# documentation build. +# +# The following CMake modules will be loaded: +# - extensions +# - python +# - west +# - root +# - zephyr_module +# +# Outcome: +# The Zephyr package required for documentation build setup. + +include_guard(GLOBAL) + +include(extensions) +include(python) +include(west) +include(root) +include(zephyr_module) diff --git a/cmake/dts.cmake b/cmake/modules/dts.cmake similarity index 98% rename from cmake/dts.cmake rename to cmake/modules/dts.cmake index 039853a69255f..f9646e5e8648f 100644 --- a/cmake/dts.cmake +++ b/cmake/modules/dts.cmake @@ -1,5 +1,13 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) +include(python) +include(boards) +include(generic_toolchain) + file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include/generated) # Zephyr code can configure itself based on a KConfig'uration with the diff --git a/cmake/extensions.cmake b/cmake/modules/extensions.cmake similarity index 98% rename from cmake/extensions.cmake rename to cmake/modules/extensions.cmake index cf2db3c098a48..99307cd5f5092 100644 --- a/cmake/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1,5 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + +# Extensions depends on two CMake modules, so load them here +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) + +# Dependencies of this module. +include(user_cache) + ######################################################## # Table of contents ######################################################## @@ -2054,81 +2063,6 @@ macro(assert_exists var) endmacro() # 3.5. File system management -function(check_if_directory_is_writeable dir ok) - execute_process( - COMMAND - ${PYTHON_EXECUTABLE} - ${ZEPHYR_BASE}/scripts/dir_is_writeable.py - ${dir} - RESULT_VARIABLE ret - ) - - if("${ret}" STREQUAL "0") - # The directory is write-able - set(${ok} 1 PARENT_SCOPE) - else() - set(${ok} 0 PARENT_SCOPE) - endif() -endfunction() - -function(find_appropriate_cache_directory dir) - set(env_suffix_LOCALAPPDATA .cache) - - if(CMAKE_HOST_APPLE) - # On macOS, ~/Library/Caches is the preferred cache directory. - set(env_suffix_HOME Library/Caches) - else() - set(env_suffix_HOME .cache) - endif() - - # Determine which env vars should be checked - if(CMAKE_HOST_APPLE) - set(dirs HOME) - elseif(CMAKE_HOST_WIN32) - set(dirs LOCALAPPDATA) - else() - # Assume Linux when we did not detect 'mac' or 'win' - # - # On Linux, freedesktop.org recommends using $XDG_CACHE_HOME if - # that is defined and defaulting to $HOME/.cache otherwise. - set(dirs - XDG_CACHE_HOME - HOME - ) - endif() - - foreach(env_var ${dirs}) - if(DEFINED ENV{${env_var}}) - set(env_dir $ENV{${env_var}}) - - set(test_user_dir ${env_dir}/${env_suffix_${env_var}}) - - check_if_directory_is_writeable(${test_user_dir} ok) - if(${ok}) - # The directory is write-able - set(user_dir ${test_user_dir}) - break() - else() - # The directory was not writeable, keep looking for a suitable - # directory - endif() - endif() - endforeach() - - # Populate local_dir with a suitable directory for caching - # files. Prefer a directory outside of the git repository because it - # is good practice to have clean git repositories. - if(DEFINED user_dir) - # Zephyr's cache files go in the "zephyr" subdirectory of the - # user's cache directory. - set(local_dir ${user_dir}/zephyr) - else() - set(local_dir ${ZEPHYR_BASE}/.cache) - endif() - - set(${dir} ${local_dir} PARENT_SCOPE) -endfunction() - function(generate_unique_target_name_from_filename filename target_name) get_filename_component(basename ${filename} NAME) string(REPLACE "." "_" x ${basename}) diff --git a/cmake/generic_toolchain.cmake b/cmake/modules/generic_toolchain.cmake similarity index 89% rename from cmake/generic_toolchain.cmake rename to cmake/modules/generic_toolchain.cmake index cea472c5a87f0..c1f930c2349ab 100644 --- a/cmake/generic_toolchain.cmake +++ b/cmake/modules/generic_toolchain.cmake @@ -1,5 +1,15 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) +include(verify-toolchain) + +# Prevent CMake from testing the toolchain +set(CMAKE_C_COMPILER_FORCED 1) +set(CMAKE_CXX_COMPILER_FORCED 1) + if(NOT TOOLCHAIN_ROOT) if(DEFINED ENV{TOOLCHAIN_ROOT}) # Support for out-of-tree toolchain diff --git a/cmake/git.cmake b/cmake/modules/git.cmake similarity index 97% rename from cmake/git.cmake rename to cmake/modules/git.cmake index fa79e30a54a4f..814fb47c41324 100644 --- a/cmake/git.cmake +++ b/cmake/modules/git.cmake @@ -10,6 +10,7 @@ # See also: independent and more static ``KERNEL_VERSION_*`` in # ``version.cmake`` and ``kernel_version.h`` +include_guard(GLOBAL) # https://cmake.org/cmake/help/latest/module/FindGit.html find_package(Git QUIET) diff --git a/cmake/host-tools.cmake b/cmake/modules/host-tools.cmake similarity index 98% rename from cmake/host-tools.cmake rename to cmake/modules/host-tools.cmake index c44251d3b93fb..abe153837cf7d 100644 --- a/cmake/host-tools.cmake +++ b/cmake/modules/host-tools.cmake @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + if(ZEPHYR_SDK_HOST_TOOLS) include(${ZEPHYR_BASE}/cmake/toolchain/zephyr/host-tools.cmake) endif() diff --git a/cmake/kconfig.cmake b/cmake/modules/kconfig.cmake similarity index 93% rename from cmake/kconfig.cmake rename to cmake/modules/kconfig.cmake index cd7ba45b70659..66aca9256ac7a 100644 --- a/cmake/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -1,5 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) +include(python) + +# autoconf.h is generated by Kconfig and placed in /zephyr/include/generated/autoconf.h. +# A project may request a custom location by setting AUTOCONF_H explicitly before +# calling 'find_package(Zephyr)' or loading this module. +set_ifndef(AUTOCONF_H ${PROJECT_BINARY_DIR}/include/generated/autoconf.h) +# Re-configure (Re-execute all CMakeLists.txt code) when autoconf.h changes +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${AUTOCONF_H}) + # Folders needed for conf/mconf files (kconfig has no method of redirecting all output files). # conf/mconf needs to be run from a different directory because of: GH-3408 file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/generated) @@ -250,6 +263,11 @@ else() set(input_configs ${DOTCONFIG}) endif() +cmake_path(GET AUTOCONF_H PARENT_PATH autoconf_h_path) +if(NOT EXISTS ${autoconf_h_path}) + file(MAKE_DIRECTORY ${autoconf_h_path}) +endif() + execute_process( COMMAND ${CMAKE_COMMAND} -E env ${COMMON_KCONFIG_ENV_SETTINGS} diff --git a/cmake/modules/kernel.cmake b/cmake/modules/kernel.cmake new file mode 100644 index 0000000000000..b0c32410f18a0 --- /dev/null +++ b/cmake/modules/kernel.cmake @@ -0,0 +1,243 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Zephyr Kernel CMake module. +# +# This is the main Zephyr Kernel CMake module which is resposible for creation +# of Zephyr libraries and the Zephyr executeable. +# +# This CMake module creates 'project(Zephyr-Kernel)' +# +# It defines properties to use while configuring libraries to be build as well +# as using add_subdirectory() to add the main /CMakeLists.txt file. +# +# Outcome: +# - Zephyr build system. +# - Zephyr project +# +# Important libraries: +# - app: This is the main application library where the application can add +# source files that must be included when building Zephyr +# +# CMake module dependencies: +# - All Zephyr CMake modules are required for this CMake module to work correctly + +include_guard(GLOBAL) + +# As this module is not intended for direct loading, but should be loaded through +# find_package(Zephyr) then it won't be loading any Zephyr CMake modules by itself. + +define_property(GLOBAL PROPERTY ZEPHYR_LIBS + BRIEF_DOCS "Global list of all Zephyr CMake libs that should be linked in" + FULL_DOCS "Global list of all Zephyr CMake libs that should be linked in. +zephyr_library() appends libs to this list.") +set_property(GLOBAL PROPERTY ZEPHYR_LIBS "") + +define_property(GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS + BRIEF_DOCS "Global list of all Zephyr interface libs that should be linked in." + FULL_DOCS "Global list of all Zephyr interface libs that should be linked in. +zephyr_interface_library_named() appends libs to this list.") +set_property(GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS "") + +define_property(GLOBAL PROPERTY GENERATED_APP_SOURCE_FILES + BRIEF_DOCS "Source files that are generated after Zephyr has been linked once." + FULL_DOCS "\ +Source files that are generated after Zephyr has been linked once.\ +May include dev_handles.c etc." + ) +set_property(GLOBAL PROPERTY GENERATED_APP_SOURCE_FILES "") + +define_property(GLOBAL PROPERTY GENERATED_KERNEL_OBJECT_FILES + BRIEF_DOCS "Object files that are generated after symbol addresses are fixed." + FULL_DOCS "\ +Object files that are generated after symbol addresses are fixed.\ +May include mmu tables, etc." + ) +set_property(GLOBAL PROPERTY GENERATED_KERNEL_OBJECT_FILES "") + +define_property(GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES + BRIEF_DOCS "Source files that are generated after symbol addresses are fixed." + FULL_DOCS "\ +Source files that are generated after symbol addresses are fixed.\ +May include isr_tables.c etc." + ) +set_property(GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES "") + +add_custom_target(code_data_relocation_target) + +# The zephyr/runners.yaml file in the build directory is used to +# configure the scripts/west_commands/runners Python package used +# by 'west flash', 'west debug', etc. +# +# This is a helper target for setting property:value pairs related to +# this file: +# +# Property Description +# -------------- -------------------------------------------------- +# bin_file "zephyr.bin" file for flashing +# hex_file "zephyr.hex" file for flashing +# elf_file "zephyr.elf" file for flashing or debugging +# yaml_contents generated contents of runners.yaml +# +# Note: there are quotes around "zephyr.bin" etc. because the actual +# paths can be changed, e.g. to flash signed versions of these files +# for consumption by bootloaders such as MCUboot. +# +# See cmake/flash/CMakeLists.txt for more details. +add_custom_target(runners_yaml_props_target) + +# CMake's 'project' concept has proven to not be very useful for Zephyr +# due in part to how Zephyr is organized and in part to it not fitting well +# with cross compilation. +# Zephyr therefore tries to rely as little as possible on project() +# and its associated variables, e.g. PROJECT_SOURCE_DIR. +# It is recommended to always use ZEPHYR_BASE instead of PROJECT_SOURCE_DIR +# when trying to reference ENV${ZEPHYR_BASE}. + +# Note any later project() resets PROJECT_SOURCE_DIR +file(TO_CMAKE_PATH "${ZEPHYR_BASE}" PROJECT_SOURCE_DIR) + +set(ZEPHYR_BINARY_DIR ${PROJECT_BINARY_DIR}) + +if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) + message(FATAL_ERROR "Source directory equals build directory.\ + In-source builds are not supported.\ + Please specify a build directory, e.g. cmake -Bbuild -H.") +endif() + +add_custom_target( + pristine + COMMAND ${CMAKE_COMMAND} -DBINARY_DIR=${APPLICATION_BINARY_DIR} + -DSOURCE_DIR=${APPLICATION_SOURCE_DIR} + -P ${ZEPHYR_BASE}/cmake/pristine.cmake + # Equivalent to rm -rf build/* + ) + +# Dummy add to generate files. +zephyr_linker_sources(SECTIONS) + +# For the gen_app_partitions.py to work correctly, we must ensure that +# all targets exports their compile commands to fetch object files. +# We enable it unconditionally, as this is also useful for several IDEs +set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE CACHE BOOL + "Export CMake compile commands. Used by gen_app_partitions.py script" + FORCE +) + +project(Zephyr-Kernel VERSION ${PROJECT_VERSION}) + +# Add .S file extension suffix into CMAKE_ASM_SOURCE_FILE_EXTENSIONS, +# because clang from OneApi can't recongnize them as asm files on +# windows now. +list(APPEND CMAKE_ASM_SOURCE_FILE_EXTENSIONS "S") +enable_language(C CXX ASM) + +# The setup / configuration of the toolchain itself and the configuration of +# supported compilation flags are now split, as this allows to use the toolchain +# for generic purposes, for example DTS, and then test the toolchain for +# supported flags at stage two. +# Testing the toolchain flags requires the enable_language() to have been called in CMake. + +# Verify that the toolchain can compile a dummy file, if it is not we +# won't be able to test for compatibility with certain C flags. +zephyr_check_compiler_flag(C "" toolchain_is_ok) +assert(toolchain_is_ok "The toolchain is unable to build a dummy C file. See CMakeError.log.") + +include(${ZEPHYR_BASE}/cmake/target_toolchain_flags.cmake) + +# 'project' sets PROJECT_BINARY_DIR to ${CMAKE_CURRENT_BINARY_DIR}, +# but for legacy reasons we need it to be set to +# ${CMAKE_CURRENT_BINARY_DIR}/zephyr +set(PROJECT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/zephyr) +set(PROJECT_SOURCE_DIR ${ZEPHYR_BASE}) + +set(KERNEL_NAME ${CONFIG_KERNEL_BIN_NAME}) + +set(KERNEL_ELF_NAME ${KERNEL_NAME}.elf) +set(KERNEL_BIN_NAME ${KERNEL_NAME}.bin) +set(KERNEL_HEX_NAME ${KERNEL_NAME}.hex) +set(KERNEL_UF2_NAME ${KERNEL_NAME}.uf2) +set(KERNEL_MAP_NAME ${KERNEL_NAME}.map) +set(KERNEL_LST_NAME ${KERNEL_NAME}.lst) +set(KERNEL_S19_NAME ${KERNEL_NAME}.s19) +set(KERNEL_EXE_NAME ${KERNEL_NAME}.exe) +set(KERNEL_STAT_NAME ${KERNEL_NAME}.stat) +set(KERNEL_STRIP_NAME ${KERNEL_NAME}.strip) +set(KERNEL_META_NAME ${KERNEL_NAME}.meta) + +include(${BOARD_DIR}/board.cmake OPTIONAL) + +# If we are using a suitable ethernet driver inside qemu, then these options +# must be set, otherwise a zephyr instance cannot receive any network packets. +# The Qemu supported ethernet driver should define CONFIG_ETH_NIC_MODEL +# string that tells what nic model Qemu should use. +if(CONFIG_QEMU_TARGET) + if ((CONFIG_NET_QEMU_ETHERNET OR CONFIG_NET_QEMU_USER) AND NOT CONFIG_ETH_NIC_MODEL) + message(FATAL_ERROR " + No Qemu ethernet driver configured! + Enable Qemu supported ethernet driver like e1000 at drivers/ethernet" + ) + elseif(CONFIG_NET_QEMU_ETHERNET) + if(CONFIG_ETH_QEMU_EXTRA_ARGS) + set(NET_QEMU_ETH_EXTRA_ARGS ",${CONFIG_ETH_QEMU_EXTRA_ARGS}") + endif() + list(APPEND QEMU_FLAGS_${ARCH} + -nic tap,model=${CONFIG_ETH_NIC_MODEL},script=no,downscript=no,ifname=${CONFIG_ETH_QEMU_IFACE_NAME}${NET_QEMU_ETH_EXTRA_ARGS} + ) + elseif(CONFIG_NET_QEMU_USER) + list(APPEND QEMU_FLAGS_${ARCH} + -nic user,model=${CONFIG_ETH_NIC_MODEL},${CONFIG_NET_QEMU_USER_EXTRA_ARGS} + ) + else() + list(APPEND QEMU_FLAGS_${ARCH} + -net none + ) + endif() +endif() + +# General purpose Zephyr target. +# This target can be used for custom zephyr settings that needs to be used elsewhere in the build system +# +# Currently used properties: +# - COMPILES_OPTIONS: Used by application memory partition feature +add_custom_target(zephyr_property_target) + +# "app" is a CMake library containing all the application code and is +# modified by the entry point ${APPLICATION_SOURCE_DIR}/CMakeLists.txt +# that was specified when cmake was called. +zephyr_library_named(app) +set_property(TARGET app PROPERTY ARCHIVE_OUTPUT_DIRECTORY app) + +add_subdirectory(${ZEPHYR_BASE} ${__build_dir}) + +# Link 'app' with the Zephyr interface libraries. +# +# NB: This must be done in boilerplate.cmake because 'app' can only be +# modified in the CMakeLists.txt file that created it. And it must be +# done after 'add_subdirectory(${ZEPHYR_BASE} ${__build_dir})' +# because interface libraries are defined while processing that +# subdirectory. +get_property(ZEPHYR_INTERFACE_LIBS_PROPERTY GLOBAL PROPERTY ZEPHYR_INTERFACE_LIBS) +foreach(boilerplate_lib ${ZEPHYR_INTERFACE_LIBS_PROPERTY}) + # Linking 'app' with 'boilerplate_lib' causes 'app' to inherit the INTERFACE + # properties of 'boilerplate_lib'. The most common property is 'include + # directories', but it is also possible to have defines and compiler + # flags in the interface of a library. + # + string(TOUPPER ${boilerplate_lib} boilerplate_lib_upper_case) # Support lowercase lib names + target_link_libraries_ifdef( + CONFIG_APP_LINK_WITH_${boilerplate_lib_upper_case} + app + PUBLIC + ${boilerplate_lib} + ) +endforeach() + +if("${CMAKE_EXTRA_GENERATOR}" STREQUAL "Eclipse CDT4") + # Call the amendment function before .project and .cproject generation + # C and CXX includes, defines in .cproject without __cplusplus + # with project includes and defines + include(${ZEPHYR_BASE}/cmake/ide/eclipse_cdt4_generator_amendment.cmake) + eclipse_cdt4_generator_amendment(1) +endif() diff --git a/cmake/python.cmake b/cmake/modules/python.cmake similarity index 98% rename from cmake/python.cmake rename to cmake/modules/python.cmake index 0ac40f9dc1102..fdc981f7a7ba0 100644 --- a/cmake/python.cmake +++ b/cmake/modules/python.cmake @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + # On Windows, instruct Python to output UTF-8 even when not # interacting with a terminal. This is required since Python scripts # are invoked by CMake code and, on Windows, standard I/O encoding defaults diff --git a/cmake/modules/root.cmake b/cmake/modules/root.cmake new file mode 100644 index 0000000000000..d5f29c8c0dde4 --- /dev/null +++ b/cmake/modules/root.cmake @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Convert Zephyr roots to absolute paths. +# +# This CMake module will convert all relative paths in existing ROOT lists to +# absolute path relative from APPLICATION_SOURCE_DIR. +# +# Optional variables: +# - ARCH_ROOT: CMake list of arch roots containing arch implementations +# - SOC_ROOT: CMake list of SoC roots containing SoC implementations +# - BOARD_ROOT: CMake list of board roots containing board and shield implementations +# - MODULE_EXT_ROOT: CMake list of module external roots containing module glue code +# +# If a root is defined it will check the list of paths in the root and convert +# any relative path to absolute path and update the root list. +# If a root is undefined it will still be undefined when this module has loaded. +# +# CMake module dependencies: +# - extensions CMake module. + +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) + +# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR +zephyr_file(APPLICATION_ROOT MODULE_EXT_ROOT) + +# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR +zephyr_file(APPLICATION_ROOT BOARD_ROOT) + +# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR +zephyr_file(APPLICATION_ROOT SOC_ROOT) + +# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR +zephyr_file(APPLICATION_ROOT ARCH_ROOT) diff --git a/cmake/modules/shields.cmake b/cmake/modules/shields.cmake new file mode 100644 index 0000000000000..86e668baefbe3 --- /dev/null +++ b/cmake/modules/shields.cmake @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Validate shields and setup shields target. +# +# This module will validate the SHIELD argument. +# +# If a shield implementation is not found for one of the specified shields an +# error will be raised and list of valid shields will be printed. +# +# Outcome: +# The following variables will be defined when this module completes: +# - shield_conf_files: List of shield specific Kconfig fragments +# - shield_dts_files : List of shield specific devicetree files +# - shield_dts_fixups: List of shield specific devicetree fixups +# +# The following targets will be defined when this module completes: +# - shields: when invoked a list of valid shields will be printed +# +# Variable dependencies: +# - BOARD_ROOT: CMake list of board roots containing board implementations +# +# Module dependencies: +# - extension module. + +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) + +# Check that SHIELD has not changed. +zephyr_check_cache(SHIELD WATCH) + +if(SHIELD) + set(BOARD_MESSAGE "${BOARD_MESSAGE}, Shield(s): ${SHIELD}") +endif() + +if(DEFINED SHIELD) + string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}") +endif() +# SHIELD-NOTFOUND is a real CMake list, from which valid shields can be popped. +# After processing all shields, only invalid shields will be left in this list. +set(SHIELD-NOTFOUND ${SHIELD_AS_LIST}) + +# Use BOARD to search for a '_defconfig' file. +# e.g. zephyr/boards/arm/96b_carbon_nrf51/96b_carbon_nrf51_defconfig. +# When found, use that path to infer the ARCH we are building for. +foreach(root ${BOARD_ROOT}) + set(shield_dir ${root}/boards/shields) + # Match the Kconfig.shield files in the shield directories to make sure we are + # finding shields, e.g. x_nucleo_iks01a1/Kconfig.shield + file(GLOB_RECURSE shields_refs_list ${shield_dir}/*/Kconfig.shield) + + # The above gives a list like + # x_nucleo_iks01a1/Kconfig.shield;x_nucleo_iks01a2/Kconfig.shield + # we construct a list of shield names by extracting the folder and find + # and overlay files in there. Each overlay corresponds to a shield. + # We obtain the shield name by removing the overlay extension. + unset(SHIELD_LIST) + foreach(shields_refs ${shields_refs_list}) + get_filename_component(shield_path ${shields_refs} DIRECTORY) + file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay) + foreach(overlay ${shield_overlays}) + get_filename_component(shield ${overlay} NAME_WE) + list(APPEND SHIELD_LIST ${shield}) + set(SHIELD_DIR_${shield} ${shield_path}) + endforeach() + endforeach() + + if(DEFINED SHIELD) + foreach(s ${SHIELD_AS_LIST}) + if(NOT ${s} IN_LIST SHIELD_LIST) + continue() + endif() + + list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) + + # if shield config flag is on, add shield overlay to the shield overlays + # list and dts_fixup file to the shield fixup file + list(APPEND + shield_dts_files + ${SHIELD_DIR_${s}}/${s}.overlay + ) + + list(APPEND + shield_dts_fixups + ${SHIELD_DIR_${s}}/dts_fixup.h + ) + + list(APPEND + SHIELD_DIRS + ${SHIELD_DIR_${s}} + ) + + # search for shield/shield.conf file + if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) + # add shield.conf to the shield config list + list(APPEND + shield_conf_files + ${SHIELD_DIR_${s}}/${s}.conf + ) + endif() + + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards + DTS shield_dts_files + KCONF shield_conf_files + ) + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} + DTS shield_dts_files + KCONF shield_conf_files + ) + endforeach() + endif() +endforeach() + +# Prepare shield usage command printing. +# This command prints all ishield in the system in the following cases: +# - User specifies an invalid SHIELD +# - User invokes ' shields' target +list(SORT SHIELD_LIST) + +if(DEFINED SHIELD AND NOT (SHIELD-NOTFOUND STREQUAL "")) + # Convert the list to pure string with newlines for printing. + string(REPLACE ";" "\n" shield_string "${SHIELD_LIST}") + + foreach (s ${SHIELD-NOTFOUND}) + message("No shield named '${s}' found") + endforeach() + message("Please choose from among the following shields:\n" + "${shield_string}" + ) + unset(CACHED_SHIELD CACHE) + message(FATAL_ERROR "Invalid SHIELD; see above.") +endif() + +# Prepend each shield with COMMAND -E echo " for printing. +# Each shield is printed as new command because build files are not fond of newlines. +list(TRANSFORM SHIELD_LIST PREPEND "COMMAND;${CMAKE_COMMAND};-E;echo;" + OUTPUT_VARIABLE shields_target_cmd +) + +add_custom_target(shields ${shields_target_cmd} USES_TERMINAL) diff --git a/cmake/modules/soc.cmake b/cmake/modules/soc.cmake new file mode 100644 index 0000000000000..48ea3736e7160 --- /dev/null +++ b/cmake/modules/soc.cmake @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Configure SoC settings based on Kconfig settings and SoC root. +# +# This CMake module will set the following variables in the build system based +# on Kconfig settings and selected SoC. +# +# If no implementation is available for the selected SoC an error will be raised. +# +# Outcome: +# The following variables will be defined when this CMake module completes: +# +# - SOC_NAME: Name of the SoC in use, identical to CONFIG_SOC +# - SOC_SERIES: Name of the SoC series in use, identical to CONFIG_SOC_SERIES +# - SOC_FAMILY: Name of the SoC family, identical to CONFIG_SOC_FAMILY +# - SOC_PATH: Path fragment defined by either SOC_NAME or SOC_FAMILY/SOC_SERIES. +# - SOC_DIR: Directory containing the SoC implementation +# +# Variable dependencies: +# - SOC_ROOT: CMake list of SoC roots containing SoC implementations +# +# Cmake module dependencies: +# - kconfig CMake module. + +include_guard(GLOBAL) + +# 'SOC_ROOT' is a prioritized list of directories where socs may be +# found. It always includes ${ZEPHYR_BASE}/soc at the lowest priority. +list(APPEND SOC_ROOT ${ZEPHYR_BASE}) + +set(SOC_NAME ${CONFIG_SOC}) +set(SOC_SERIES ${CONFIG_SOC_SERIES}) +set(SOC_TOOLCHAIN_NAME ${CONFIG_SOC_TOOLCHAIN_NAME}) +set(SOC_FAMILY ${CONFIG_SOC_FAMILY}) + +if("${SOC_SERIES}" STREQUAL "") + set(SOC_PATH ${SOC_NAME}) +else() + set(SOC_PATH ${SOC_FAMILY}/${SOC_SERIES}) +endif() + +# Use SOC to search for a 'CMakeLists.txt' file. +# e.g. zephyr/soc/xtense/intel_apl_adsp/CMakeLists.txt. +foreach(root ${SOC_ROOT}) + # Check that the root looks reasonable. + if(NOT IS_DIRECTORY "${root}/soc") + message(WARNING "\nSOC_ROOT element(s) without a 'soc' subdirectory: +${root} +Hints: + - if your SoC family directory is '/foo/bar/soc//my_soc_family', then add '/foo/bar' to SOC_ROOT, not the entire SoC family path + - if in doubt, use absolute paths\n") + endif() + + if(EXISTS ${root}/soc/${ARCH}/${SOC_PATH}) + set(SOC_DIR ${root}/soc) + break() + endif() +endforeach() + +if(NOT SOC_DIR) + message(FATAL_ERROR "Could not find SOC=${SOC_NAME} for BOARD=${BOARD},\n" + "please check your installation.\n" + "SOC roots searched:\n" + "${SOC_ROOT}\n" + ) +endif() diff --git a/cmake/target_toolchain.cmake b/cmake/modules/target_toolchain.cmake similarity index 92% rename from cmake/target_toolchain.cmake rename to cmake/modules/target_toolchain.cmake index 0d8bbc2d32d0c..9c9d4d8d74387 100644 --- a/cmake/target_toolchain.cmake +++ b/cmake/modules/target_toolchain.cmake @@ -1,5 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + +# Prevent CMake from testing the toolchain +set(CMAKE_C_COMPILER_FORCED 1) +set(CMAKE_CXX_COMPILER_FORCED 1) + # No official documentation exists for the "Generic" value, except their wiki. # # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/CrossCompiling: @@ -56,5 +62,5 @@ add_custom_target(bintools) include(${TOOLCHAIN_ROOT}/cmake/compiler/${COMPILER}/target.cmake OPTIONAL) include(${TOOLCHAIN_ROOT}/cmake/linker/${LINKER}/target.cmake OPTIONAL) -include(${CMAKE_CURRENT_LIST_DIR}/bintools/bintools_template.cmake) +include(${ZEPHYR_BASE}/cmake/bintools/bintools_template.cmake) include(${TOOLCHAIN_ROOT}/cmake/bintools/${BINTOOLS}/target.cmake OPTIONAL) diff --git a/subsys/testsuite/unittest.cmake b/cmake/modules/unittest.cmake similarity index 100% rename from subsys/testsuite/unittest.cmake rename to cmake/modules/unittest.cmake diff --git a/cmake/modules/user_cache.cmake b/cmake/modules/user_cache.cmake new file mode 100644 index 0000000000000..d3f401e33948d --- /dev/null +++ b/cmake/modules/user_cache.cmake @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# Configure user cache directory. +# +# The user cache can be used for caching of data that should be persistent +# across builds to speed up CMake configure / build system generation and/or +# compilation. +# +# Only data that can be safely re-generated should be placed in this cache. +# +# Zephyr build system uses this user cache to store Zephyr compiler check +# results which significantly improve toolchain testing performance. +# See https://github.com/zephyrproject-rtos/zephyr/pull/7102 for details. +# +# Outcome: +# The following variables will be defined when this CMake module completes: +# +# - USER_CACHE_DIR: User cache directory in use. +# +# CMake module dependencies: +# - python CMake module. + +include_guard(GLOBAL) + +# Dependencies of this module. +include(python) + +function(find_appropriate_cache_directory dir) + set(env_suffix_LOCALAPPDATA .cache) + + if(CMAKE_HOST_APPLE) + # On macOS, ~/Library/Caches is the preferred cache directory. + set(env_suffix_HOME Library/Caches) + else() + set(env_suffix_HOME .cache) + endif() + + # Determine which env vars should be checked + if(CMAKE_HOST_APPLE) + set(dirs HOME) + elseif(CMAKE_HOST_WIN32) + set(dirs LOCALAPPDATA) + else() + # Assume Linux when we did not detect 'mac' or 'win' + # + # On Linux, freedesktop.org recommends using $XDG_CACHE_HOME if + # that is defined and defaulting to $HOME/.cache otherwise. + set(dirs + XDG_CACHE_HOME + HOME + ) + endif() + + foreach(env_var ${dirs}) + if(DEFINED ENV{${env_var}}) + set(env_dir $ENV{${env_var}}) + + set(test_user_dir ${env_dir}/${env_suffix_${env_var}}) + + execute_process(COMMAND ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/dir_is_writeable.py ${test_user_dir} + RESULT_VARIABLE writable_result + ) + if("${writable_result}" STREQUAL "0") + # The directory is write-able + set(user_dir ${test_user_dir}) + break() + else() + # The directory was not writeable, keep looking for a suitable + # directory + endif() + endif() + endforeach() + + # Populate local_dir with a suitable directory for caching + # files. Prefer a directory outside of the git repository because it + # is good practice to have clean git repositories. + if(DEFINED user_dir) + # Zephyr's cache files go in the "zephyr" subdirectory of the + # user's cache directory. + set(local_dir ${user_dir}/zephyr) + else() + set(local_dir ${ZEPHYR_BASE}/.cache) + endif() + + set(${dir} ${local_dir} PARENT_SCOPE) +endfunction() + +# Populate USER_CACHE_DIR with a directory that user applications may +# write cache files to. +if(NOT DEFINED USER_CACHE_DIR) + find_appropriate_cache_directory(USER_CACHE_DIR) +endif() +message(STATUS "Cache files will be written to: ${USER_CACHE_DIR}") diff --git a/cmake/verify-toolchain.cmake b/cmake/modules/verify-toolchain.cmake similarity index 99% rename from cmake/verify-toolchain.cmake rename to cmake/modules/verify-toolchain.cmake index 7dce062d5046d..06a01b7abb261 100644 --- a/cmake/verify-toolchain.cmake +++ b/cmake/modules/verify-toolchain.cmake @@ -15,6 +15,8 @@ # it takes the following arguments: # FORMAT=json: Print the output as a json formatted string, useful for Python +include_guard(GLOBAL) + # This is the minimum required Zephyr-SDK version which supports CMake package set(TOOLCHAIN_ZEPHYR_MINIMUM_REQUIRED_VERSION 0.13.1) diff --git a/cmake/version.cmake b/cmake/modules/version.cmake similarity index 90% rename from cmake/version.cmake rename to cmake/modules/version.cmake index 326a33ca2a271..666adc3e4bd53 100644 --- a/cmake/version.cmake +++ b/cmake/modules/version.cmake @@ -26,6 +26,11 @@ # See also: independent and more dynamic ``BUILD_VERSION`` in # ``git.cmake``. +# Note: version.cmake is loaded multiple times by ZephyrConfigVersion.cmake to +# determine this Zephyr package version and thus the correct Zephyr CMake +# package to load. +# Therefore `version.cmake` should not use include_guard(GLOBAL). +# The final load of `version.cmake` will setup correct build version values. include(${ZEPHYR_BASE}/cmake/hex.cmake) file(READ ${ZEPHYR_BASE}/VERSION ver) diff --git a/cmake/west.cmake b/cmake/modules/west.cmake similarity index 98% rename from cmake/west.cmake rename to cmake/modules/west.cmake index 79479ae1316b9..cffeb35b18d23 100644 --- a/cmake/west.cmake +++ b/cmake/modules/west.cmake @@ -1,5 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + +# Dependencies of this module. +include(python) + # west is an optional dependency. We need to run west using the same # Python interpreter as everything else, though, so we play some extra # tricks. diff --git a/cmake/modules/zephyr_default.cmake b/cmake/modules/zephyr_default.cmake new file mode 100644 index 0000000000000..b42f0f31c71b9 --- /dev/null +++ b/cmake/modules/zephyr_default.cmake @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2021, Nordic Semiconductor ASA + +# This CMake module will load all Zephyr CMake modules in correct order for +# default Zephyr build system. +# +# Outcome: +# See individual CMake module descriptions + +include_guard(GLOBAL) + +# The code line below defines the real minimum supported CMake version. +# +# Unfortunately CMake requires the toplevel CMakeLists.txt file to define the +# required version, not even invoking it from a CMake module is sufficient. +# It is however permitted to have multiple invocations of cmake_minimum_required. +cmake_minimum_required(VERSION 3.20.0) + +message(STATUS "Application: ${APPLICATION_SOURCE_DIR}") + +find_package(ZephyrBuildConfiguration + QUIET NO_POLICY_SCOPE + NAMES ZephyrBuild + PATHS ${ZEPHYR_BASE}/../* + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_PACKAGE_REGISTRY + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_SYSTEM_PACKAGE_REGISTRY +) + +# Load Zephyr extensions +include(extensions) +include(git) +include(version) # depends on hex.cmake + +# +# Find tools +# + +include(python) +include(west) +include(ccache) + +# Load default root settings +include(root) + +# +# Find Zephyr modules. +# Those may contain additional DTS, BOARD, SOC, ARCH ROOTs. +# Also create the Kconfig binary dir for generated Kconf files. +# +include(zephyr_module) + +include(boards) +include(shields) +include(arch) +include(build_configuration) + +include(user_cache) +include(verify-toolchain) +include(host-tools) + +# Include board specific device-tree flags before parsing. +include(${BOARD_DIR}/pre_dt_board OPTIONAL) + +# DTS should be close to kconfig because CONFIG_ variables from +# kconfig and dts should be available at the same time. +# +# The DT system uses a C preprocessor for it's code generation needs. +# This creates an awkward chicken-and-egg problem, because we don't +# always know exactly which toolchain the user needs until we know +# more about the target, e.g. after DT and Kconfig. +# +# To resolve this we find "some" C toolchain, configure it generically +# with the minimal amount of configuration needed to have it +# preprocess DT sources, and then, after we have finished processing +# both DT and Kconfig we complete the target-specific configuration, +# and possibly change the toolchain. +include(generic_toolchain) +include(dts) +include(kconfig) +include(soc) +include(target_toolchain) +include(kernel) diff --git a/cmake/zephyr_module.cmake b/cmake/modules/zephyr_module.cmake similarity index 77% rename from cmake/zephyr_module.cmake rename to cmake/modules/zephyr_module.cmake index 21850f908fa12..31c40af5e606d 100644 --- a/cmake/zephyr_module.cmake +++ b/cmake/modules/zephyr_module.cmake @@ -1,19 +1,25 @@ # SPDX-License-Identifier: Apache-2.0 +include_guard(GLOBAL) + +# Dependencies of this module. +include(extensions) +include(python) + # This cmake file provides functionality to import CMakeLists.txt and Kconfig # files for Zephyr modules into Zephyr build system. # -# CMakeLists.txt and Kconfig files can reside directly in the module or in a -# MODULE_EXT_ROOT. +# CMakeLists.txt and Kconfig files can reside directly in the Zephyr module or +# in a MODULE_EXT_ROOT. # The `/zephyr/module.yml` file specifies whether the build files are -# located in the module or in a MODULE_EXT_ROOT. +# located in the Zephyr module or in a MODULE_EXT_ROOT. # # A list of Zephyr modules can be provided to the build system using: # -DZEPHYR_MODULES=[;] # # It looks for: /zephyr/module.yml or # /zephyr/CMakeLists.txt -# to load the module into Zephyr build system. +# to load the Zephyr module into Zephyr build system. # If west is available, it uses `west list` to obtain a list of projects to # search for zephyr/module.yml # @@ -23,6 +29,17 @@ # - `ZEPHYR__KCONFIG` is used for inclusion of the Kconfig # files into the build system. +# Settings used by Zephyr module but where systems may define an alternative value. +set_ifndef(KCONFIG_BINARY_DIR ${CMAKE_BINARY_DIR}/Kconfig) + +if(ZEPHYR_EXTRA_MODULES) + # ZEPHYR_EXTRA_MODULES has either been specified on the cmake CLI or is + # already in the CMakeCache.txt. This has precedence over the environment + # variable ZEPHYR_EXTRA_MODULES +elseif(DEFINED ENV{ZEPHYR_EXTRA_MODULES}) + set(ZEPHYR_EXTRA_MODULES $ENV{ZEPHYR_EXTRA_MODULES}) +endif() + if(ZEPHYR_MODULES) set(ZEPHYR_MODULES_ARG "--modules" ${ZEPHYR_MODULES}) endif() @@ -31,6 +48,7 @@ if(ZEPHYR_EXTRA_MODULES) set(ZEPHYR_EXTRA_MODULES_ARG "--extra-modules" ${ZEPHYR_EXTRA_MODULES}) endif() +file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}) set(KCONFIG_MODULES_FILE ${KCONFIG_BINARY_DIR}/Kconfig.modules) set(ZEPHYR_SETTINGS_FILE ${CMAKE_BINARY_DIR}/zephyr_settings.txt) @@ -69,17 +87,13 @@ if(WEST OR ZEPHYR_MODULES) # lazy regexes (it supports greedy only). string(REGEX REPLACE "\"(.*)\":\".*\"" "\\1" key ${setting}) string(REGEX REPLACE "\".*\":\"(.*)\"" "\\1" value ${setting}) - # MODULE_EXT_ROOT is process order which means module roots processed - # later wins. To ensure ZEPHYR_BASE stays first, and command line settings - # are processed last, we insert at position 1. - if ("${key}" STREQUAL "MODULE_EXT_ROOT") - list(INSERT ${key} 1 ${value}) - else() - list(APPEND ${key} ${value}) - endif() + list(APPEND ${key} ${value}) endforeach() endif() + # Append ZEPHYR_BASE as a default ext root at lowest priority + list(APPEND MODULE_EXT_ROOT ${ZEPHYR_BASE}) + if(EXISTS ${CMAKE_BINARY_DIR}/zephyr_modules.txt) file(STRINGS ${CMAKE_BINARY_DIR}/zephyr_modules.txt ZEPHYR_MODULES_TXT ENCODING UTF-8) @@ -94,6 +108,9 @@ if(WEST OR ZEPHYR_MODULES) endforeach() endif() + # MODULE_EXT_ROOT is process order which means Zephyr module roots processed + # later wins. therefore we reverse the list before processing. + list(REVERSE MODULE_EXT_ROOT) foreach(root ${MODULE_EXT_ROOT}) if(NOT EXISTS ${root}) message(FATAL_ERROR "No `modules.cmake` found in module root `${root}`.") @@ -105,8 +122,8 @@ if(WEST OR ZEPHYR_MODULES) if(DEFINED ZEPHYR_MODULES_TXT) foreach(module ${ZEPHYR_MODULES_TXT}) # Match "":"" for each line of file, each corresponding to - # one module. The use of quotes is required due to CMake not supporting - # lazy regexes (it supports greedy only). + # one Zephyr module. The use of quotes is required due to CMake not + # supporting lazy regexes (it supports greedy only). string(CONFIGURE ${module} module) string(REGEX REPLACE "\"(.*)\":\".*\":\".*\"" "\\1" module_name ${module}) string(REGEX REPLACE "\".*\":\"(.*)\":\".*\"" "\\1" module_path ${module}) @@ -126,7 +143,7 @@ ${MODULE_NAME_UPPER} is a restricted name for Zephyr modules as it is used for \ else() file(WRITE ${KCONFIG_MODULES_FILE} - "# No west and no modules\n" + "# No west and no Zephyr modules\n" ) endif() diff --git a/cmake/shields.cmake b/cmake/shields.cmake deleted file mode 100644 index 2ea062bdc6038..0000000000000 --- a/cmake/shields.cmake +++ /dev/null @@ -1,18 +0,0 @@ -if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE) - # This file was invoked as a script directly with -P: - # cmake -P shields.cmake - # - # Unlike boards.cmake, this takes no OUTPUT_FILE option, but - # SHIELD_LIST_SPACE_SEPARATED is required. - list(SORT SHIELD_LIST) - foreach(shield ${SHIELD_LIST}) - message("${shield}") - endforeach() -else() - # This file was included into usage.cmake. - set(sorted_shield_list ${SHIELD_LIST}) - list(SORT sorted_shield_list) - foreach(shield ${sorted_shield_list}) - list(APPEND sorted_shield_cmds COMMAND ${CMAKE_COMMAND} -E echo "${shield}") - endforeach() -endif() diff --git a/cmake/usage/CMakeLists.txt b/cmake/usage/CMakeLists.txt index 88ccbd7984371..5205b71353bc1 100644 --- a/cmake/usage/CMakeLists.txt +++ b/cmake/usage/CMakeLists.txt @@ -1,15 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -include (${ZEPHYR_BASE}/cmake/shields.cmake) -include (${ZEPHYR_BASE}/cmake/boards.cmake) - -# shields.cmake and boards.cmake can be run with cmake -P for printing -# help output on user error when settings BOARD or SHIELD, and -# add_custom_target() is not available in script mode, so we place -# them in here. -add_custom_target(shields ${sorted_shield_cmds} USES_TERMINAL) -add_custom_target(boards ${list_boards_commands} USES_TERMINAL) - add_custom_target( usage ${CMAKE_COMMAND} diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index fd20f6dce5c49..1a8fffb5529f9 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -3,8 +3,7 @@ cmake_minimum_required(VERSION 3.20.0) project(Zephyr-Kernel-Doc LANGUAGES) -set(NO_BOILERPLATE TRUE) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} ..) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} .. COMPONENTS doc) file(TO_CMAKE_PATH "${ZEPHYR_BASE}" ZEPHYR_BASE) message(STATUS "Zephyr base: ${ZEPHYR_BASE}") @@ -36,11 +35,6 @@ if(NOT LATEX_PDFLATEX_FOUND OR NOT LATEXMK) message(WARNING "LaTeX components not found. PDF build will not be available.") endif() -include(${ZEPHYR_BASE}/cmake/python.cmake) - -# Find west to (optionally) process modules for Kconfig -find_program(WEST west) - #------------------------------------------------------------------------------- # Environment & Paths @@ -103,11 +97,6 @@ set_target_properties( # kconfig set(KCONFIG_BINARY_DIR ${CMAKE_BINARY_DIR}/Kconfig) -list(INSERT MODULE_EXT_ROOT 0 ${ZEPHYR_BASE}) -file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}) - -include(${ZEPHYR_BASE}/cmake/extensions.cmake) -include(${ZEPHYR_BASE}/cmake/zephyr_module.cmake) foreach(module_name ${ZEPHYR_MODULE_NAMES}) zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) diff --git a/scripts/pylib/twister/twisterlib.py b/scripts/pylib/twister/twisterlib.py index 512b6f51ad692..980e7cf181967 100755 --- a/scripts/pylib/twister/twisterlib.py +++ b/scripts/pylib/twister/twisterlib.py @@ -3025,7 +3025,7 @@ def get_all_tests(self): @staticmethod def get_toolchain(): - toolchain_script = Path(ZEPHYR_BASE) / Path('cmake/verify-toolchain.cmake') + toolchain_script = Path(ZEPHYR_BASE) / Path('cmake/modules/verify-toolchain.cmake') result = CMake.run_cmake_script([toolchain_script, "FORMAT=json"]) try: diff --git a/share/zephyr-package/cmake/ZephyrConfig.cmake b/share/zephyr-package/cmake/ZephyrConfig.cmake index 7c1e6212ba7bc..22e5089d56ad8 100644 --- a/share/zephyr-package/cmake/ZephyrConfig.cmake +++ b/share/zephyr-package/cmake/ZephyrConfig.cmake @@ -11,17 +11,48 @@ # It will be empty if not set in environment. macro(include_boilerplate location) + list(PREPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/cmake/modules) if(ZEPHYR_UNITTEST) + message(WARNING "The ZephyrUnittest CMake package has been deprecated.\n" + "ZephyrUnittest has been replaced with Zephyr CMake module 'unittest' \n" + "and can be loaded as: 'find_package(Zephyr COMPONENTS unittest)'" + ) set(ZephyrUnittest_FOUND True) - set(BOILERPLATE_FILE ${ZEPHYR_BASE}/subsys/testsuite/unittest.cmake) + set(Zephyr_FIND_COMPONENTS unittest) else() set(Zephyr_FOUND True) - set(BOILERPLATE_FILE ${ZEPHYR_BASE}/cmake/app/boilerplate.cmake) endif() + if(NOT DEFINED APPLICATION_SOURCE_DIR) + set(APPLICATION_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH + "Application Source Directory" + ) + endif() + + if(NOT DEFINED APPLICATION_BINARY_DIR) + set(APPLICATION_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH + "Application Binary Directory" + ) + endif() + + set(__build_dir ${APPLICATION_BINARY_DIR}/zephyr) + set(PROJECT_BINARY_DIR ${__build_dir}) + if(NOT NO_BOILERPLATE) - message("Including boilerplate (${location}): ${BOILERPLATE_FILE}") - include(${BOILERPLATE_FILE} NO_POLICY_SCOPE) + list(LENGTH Zephyr_FIND_COMPONENTS components_length) + if(components_length EQUAL 0) + message("Loading Zephyr default modules (${location}).") + include(zephyr_default NO_POLICY_SCOPE) + else() + message("Loading Zephyr module(s) (${location}): ${Zephyr_FIND_COMPONENTS}") + foreach(component ${Zephyr_FIND_COMPONENTS}) + include(${component}) + endforeach() + endif() + else() + message(WARNING "The NO_BOILERPLATE setting has been deprecated.\n" + "Please use: 'find_package(Zephyr COMPONENTS )'" + ) endif() endmacro() diff --git a/share/zephyr-package/cmake/ZephyrConfigVersion.cmake b/share/zephyr-package/cmake/ZephyrConfigVersion.cmake index 9292f0a58ea4e..5b9472b1ebb9e 100644 --- a/share/zephyr-package/cmake/ZephyrConfigVersion.cmake +++ b/share/zephyr-package/cmake/ZephyrConfigVersion.cmake @@ -56,7 +56,7 @@ if((DEFINED ZEPHYR_BASE) OR (DEFINED ENV_ZEPHYR_BASE)) # We are the Zephyr to be used set(NO_PRINT_VERSION True) - include(${ZEPHYR_BASE}/cmake/version.cmake) + include(${ZEPHYR_BASE}/cmake/modules/version.cmake) # Zephyr uses project version, but CMake package uses PACKAGE_VERSION set(PACKAGE_VERSION ${PROJECT_VERSION}) check_zephyr_version() @@ -93,7 +93,7 @@ set(ZEPHYR_BASE ${CURRENT_ZEPHYR_DIR}) # Tell version.cmake to not print as printing version for all Zephyr installations being tested # will lead to confusion on which is being used. set(NO_PRINT_VERSION True) -include(${ZEPHYR_BASE}/cmake/version.cmake) +include(${ZEPHYR_BASE}/cmake/modules/version.cmake) # Zephyr uses project version, but CMake package uses PACKAGE_VERSION set(PACKAGE_VERSION ${PROJECT_VERSION}) set(ZEPHYR_BASE) From d69d1e79c2a97f91bdc29d3dd3770228f2341501 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Thu, 20 Jan 2022 22:10:56 +0100 Subject: [PATCH 8/8] samples: rpi_pico: create dedicated boards/rpi_pico/boot_stage2 sample This commit removes the multi-image stage2 bootloader from the Zephyr image and instead create a dedicated board specific sample for the stage2 bootloader. It reuses the Zephyr build infrastructure, such as Zephyr modules, toolchain, Kconfig, etc. but not the Zephyr kernel itself. Signed-off-by: Torsten Rasmussen --- modules/hal_rpi_pico/CMakeLists.txt | 42 ----------- .../rpi_pico/boot_stage2/CMakeLists.txt | 75 +++++++++++++++++++ samples/boards/rpi_pico/boot_stage2/prj.conf | 1 + 3 files changed, 76 insertions(+), 42 deletions(-) create mode 100644 samples/boards/rpi_pico/boot_stage2/CMakeLists.txt create mode 100644 samples/boards/rpi_pico/boot_stage2/prj.conf diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt index 78609df7a78a6..28269f033a054 100644 --- a/modules/hal_rpi_pico/CMakeLists.txt +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -8,53 +8,11 @@ if(CONFIG_HAS_RPI_PICO) set(common_dir ${ZEPHYR_HAL_RPI_PICO_MODULE_DIR}/src/common) set(boot_stage_dir ${rp2_common_dir}/boot_stage2) - # Compile the second stage bootloader as a separate executable - - add_executable(boot_stage2) - - target_sources_ifdef(CONFIG_RP2_FLASH_W25Q080 boot_stage2 PRIVATE - ${boot_stage_dir}/boot2_w25q080.S) - target_sources_ifdef(CONFIG_RP2_FLASH_GENERIC_03H boot_stage2 PRIVATE - ${boot_stage_dir}/boot2_generic_03h.S) - target_sources_ifdef(CONFIG_RP2_FLASH_IS25LP080 boot_stage2 PRIVATE - ${boot_stage_dir}/boot2_is25lp080.S) - target_sources_ifdef(CONFIG_RP2_FLASH_W25X10CL boot_stage2 PRIVATE - ${boot_stage_dir}/boot2_w25x10cl.S) - - target_include_directories(boot_stage2 PUBLIC - ${CMAKE_CURRENT_LIST_DIR} - ${boot_stage_dir}/asminclude - ${rp2_common_dir}/pico_platform/include - ${rp2040_dir}/hardware_regs/include - ${common_dir}/pico_base/include - ) - - target_link_options(boot_stage2 PRIVATE - "-nostartfiles" - "--specs=nosys.specs" - "LINKER:--script=${boot_stage_dir}/boot_stage2.ld" - ) - - # Generates a binary file from the compiled bootloader - add_custom_target(bootloader_bin ALL DEPENDS boot_stage2.bin) - add_custom_command(OUTPUT boot_stage2.bin - DEPENDS boot_stage2 - COMMAND ${CMAKE_OBJCOPY} -Obinary $ boot_stage2.bin - ) - - # Checksums the binary, pads it, and generates an assembly file - add_custom_target(boot_stage2_asm ALL DEPENDS boot_stage2.S) - add_custom_command(OUTPUT boot_stage2.S - DEPENDS boot_stage2.bin - COMMAND ${Python3_EXECUTABLE} ${boot_stage_dir}/pad_checksum - -s 0xffffffff boot_stage2.bin boot_stage2.S) - # Pico sources and headers necessary for every build. # These contain definitions and implementation used mostly for # initializing the SoC, and therefore are always required. zephyr_library_sources( - boot_stage2.S ${rp2_common_dir}/hardware_clocks/clocks.c ${rp2_common_dir}/hardware_pll/pll.c ${rp2_common_dir}/hardware_xosc/xosc.c diff --git a/samples/boards/rpi_pico/boot_stage2/CMakeLists.txt b/samples/boards/rpi_pico/boot_stage2/CMakeLists.txt new file mode 100644 index 0000000000000..76e074c68a080 --- /dev/null +++ b/samples/boards/rpi_pico/boot_stage2/CMakeLists.txt @@ -0,0 +1,75 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +# This is not a Zephyr sample, but a minimal stage2 bootloader. +# However, we reuse the Zephyr build infrastructure for Zephyr modules, +# board processing, toolchain and other related tools +# List of Zephyr CMake modules required. +set(zephyr_cmake_modules extensions west root zephyr_module boards shields arch + build_configuration host-tools generic_toolchain kconfig soc target_toolchain +) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} COMPONENTS ${zephyr_cmake_modules}) +project(rpi_boot2) + +enable_language(C CXX ASM) + +# Test the toolchain. +zephyr_check_compiler_flag(C "" toolchain_is_ok) +assert(toolchain_is_ok "The toolchain is unable to build a dummy C file. See CMakeError.log.") + +# Load flash and friends. +add_subdirectory(${ZEPHYR_BASE}/cmake/flash flash) + +set(rp2_common_dir ${ZEPHYR_HAL_RPI_PICO_MODULE_DIR}/src/rp2_common) +set(rp2040_dir ${ZEPHYR_HAL_RPI_PICO_MODULE_DIR}/src/rp2040) +set(common_dir ${ZEPHYR_HAL_RPI_PICO_MODULE_DIR}/src/common) +set(boot_stage_dir ${rp2_common_dir}/boot_stage2) + +# Compile the second stage bootloader + +add_executable(boot_stage2) + +target_sources_ifdef(CONFIG_RP2_FLASH_W25Q080 boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_w25q080.S) +target_sources_ifdef(CONFIG_RP2_FLASH_GENERIC_03H boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_generic_03h.S) +target_sources_ifdef(CONFIG_RP2_FLASH_IS25LP080 boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_is25lp080.S) +target_sources_ifdef(CONFIG_RP2_FLASH_W25X10CL boot_stage2 PRIVATE + ${boot_stage_dir}/boot2_w25x10cl.S) + +target_include_directories(boot_stage2 PUBLIC + ${ZEPHYR_BASE}/modules/hal_rpi_pico + ${boot_stage_dir}/asminclude + ${rp2_common_dir}/pico_platform/include + ${rp2040_dir}/hardware_regs/include + ${common_dir}/pico_base/include + ) + +target_link_options(boot_stage2 PRIVATE + "-nostartfiles" + "--specs=nosys.specs" + "LINKER:--script=${boot_stage_dir}/boot_stage2.ld" + ) + +# Generates a binary file from the compiled bootloader +add_custom_target(bootloader_bin ALL DEPENDS boot_stage2.bin) +add_custom_command(OUTPUT boot_stage2.bin + DEPENDS boot_stage2 + COMMAND ${CMAKE_OBJCOPY} -Obinary $ boot_stage2.bin + ) + +# @yonsh I assume you still will need to pad checksum, and then convert the +# final result to a hex or bin file before flashing, correct ? +# Checksums the binary, pads it, and generates an assembly file +#add_custom_target(boot_stage2_asm ALL DEPENDS boot_stage2.S) +#add_custom_command(OUTPUT boot_stage2.S +# DEPENDS boot_stage2.bin +# COMMAND ${Python3_EXECUTABLE} ${boot_stage_dir}/pad_checksum +# -s 0xffffffff boot_stage2.bin boot_stage2.S) diff --git a/samples/boards/rpi_pico/boot_stage2/prj.conf b/samples/boards/rpi_pico/boot_stage2/prj.conf new file mode 100644 index 0000000000000..b95f805a06e27 --- /dev/null +++ b/samples/boards/rpi_pico/boot_stage2/prj.conf @@ -0,0 +1 @@ +CONFIG_UART_CONSOLE=n