diff --git a/CMakeLists.txt b/CMakeLists.txt index 36bc079a9448a..ba46fcae5b67c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1454,12 +1454,27 @@ if(CONFIG_BUILD_OUTPUT_BIN) endif() if(CONFIG_BUILD_OUTPUT_BIN AND CONFIG_BUILD_OUTPUT_UF2) + if(CONFIG_BUILD_OUTPUT_UF2_USE_FLASH_BASE) + set(flash_addr "${CONFIG_FLASH_BASE_ADDRESS}") + else() + set(flash_addr "${CONFIG_FLASH_LOAD_OFFSET}") + endif() + + if(CONFIG_BUILD_OUTPUT_UF2_USE_FLASH_OFFSET) + # Note, the `+ 0` in formula below avoids errors in cases where a Kconfig + # variable is undefined and thus expands to nothing. + math(EXPR flash_addr + "${flash_addr} + ${CONFIG_FLASH_LOAD_OFFSET} + 0" + OUTPUT_FORMAT HEXADECIMAL + ) + endif() + list(APPEND post_build_commands COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/uf2conv.py -c -f ${CONFIG_BUILD_OUTPUT_UF2_FAMILY_ID} - -b ${CONFIG_FLASH_LOAD_OFFSET} + -b ${flash_addr} -o ${KERNEL_UF2_NAME} ${KERNEL_BIN_NAME} ) diff --git a/CODEOWNERS b/CODEOWNERS index 04f7c19f02bee..7f2a14e534570 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -46,6 +46,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 @@ -129,6 +130,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 @@ -265,6 +267,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 @@ -353,6 +356,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 @@ -448,6 +452,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 @@ -489,6 +494,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/Kconfig.zephyr b/Kconfig.zephyr index ecc92df362b54..3d41b8dce96fc 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -462,6 +462,7 @@ config BUILD_OUTPUT_UF2_FAMILY_ID default "0xada52840" if SOC_NRF52840_QIAA default "0x4fb2d5bd" if SOC_SERIES_IMX_RT default "0x2abc77ec" if SOC_SERIES_LPC55XXX + default "0xe48bff56" if SOC_SERIES_RP2XXX default "0x68ed2b88" if SOC_SERIES_SAMD21 default "0x55114460" if SOC_SERIES_SAMD51 default "0x647824b6" if SOC_SERIES_STM32F0X @@ -486,6 +487,14 @@ config BUILD_OUTPUT_UF2_FAMILY_ID name string. If the SoC in use is known by UF2, the Family ID will be pre-filled with the known value. +config BUILD_OUTPUT_UF2_USE_FLASH_BASE + bool + default n + +config BUILD_OUTPUT_UF2_USE_FLASH_OFFSET + bool + default n + endif # BUILD_OUTPUT_UF2 config BUILD_OUTPUT_STRIPPED 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 0000000000000..0b223bb334bd9 Binary files /dev/null and b/boards/arm/rpi_pico/doc/img/rpi_pico.png differ diff --git a/boards/arm/rpi_pico/doc/index.rst b/boards/arm/rpi_pico/doc/index.rst new file mode 100644 index 0000000000000..75f525275cd13 --- /dev/null +++ b/boards/arm/rpi_pico/doc/index.rst @@ -0,0 +1,119 @@ +.. _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` + +Programming and Debugging +************************* + +Flashing +======== + +Using an SWD adapter +-------------------- + +The Raspberry Pi Pico has an SWD interface that can be used to program +and debug the on board RP2040. This interface can be utilized by openocd. +However, to use it with the RP2040, a custom fork of openocd is needed. +This fork can be found here: https://github.com/raspberrypi/openocd + +Depending on the interface used (such as JLink), you might need to +checkout to a branch that supports this interface, before proceeding. +Build and install openocd as described in the README. + +When openocd is installed, you can flash the board with the following +command (assuming JLink is used): + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -c 'transport select swd' -f target/rp2040.cfg -c "adapter speed 2000" -c 'targets rp2040.core0' -c 'program path/to/zephyr.elf verify reset exit' + +Using UF2 +--------- + +If you don't have an SWD adapter, you can flash the Raspberry Pi Pico with +a UF2 file. By default, building an app for this board will generate a +`build/zephyr/zephyr.uf2` file. If the Pico is powered on with the `BOOTSEL` +button pressed, it will appear on the host as a mass storage device. The +UF2 file should be drag-and-dropped to the device, which will flash the Pico. + +Debugging +========= + +The SWD interface can also be used to debug the board. To achieve this, +install openocd as described for flashing the board. Also, install gdb-multiarch. +Then run the following command: + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -c 'transport select swd' -f target/rp2040.cfg -c "adapter speed 2000" -c 'targets rp2040.core0' + +On another terminal, run: + +.. code-block:: console + + $ gdb-multiarch + +Inside gdb, run: + +.. code-block:: console + + (gdb) tar ext :3333 + (gdb) file path/to/zephyr.elf + +You can then start debugging the board. 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..32bfeb84af993 --- /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 */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + 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..f9080da08cebc --- /dev/null +++ b/boards/arm/rpi_pico/rpi_pico.yaml @@ -0,0 +1,13 @@ +identifier: rpi_pico +name: RaspberryPi-Pico +type: mcu +arch: arm +flash: 2048 +ram: 264 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart + - gpio diff --git a/boards/arm/rpi_pico/rpi_pico_defconfig b/boards/arm/rpi_pico/rpi_pico_defconfig new file mode 100644 index 0000000000000..11cb1780ee8fc --- /dev/null +++ b/boards/arm/rpi_pico/rpi_pico_defconfig @@ -0,0 +1,9 @@ +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 +CONFIG_BUILD_OUTPUT_UF2=y 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..3593076d9dbed --- /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/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..97ed9d54e6fe7 --- /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/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 new file mode 100644 index 0000000000000..72d6efeb712c5 --- /dev/null +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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>; + }; + + pinctrl: pin-controller@40014000 { + compatible = "raspberrypi,pico-pinctrl"; + reg = <0x40014000 DT_SIZE_K(4)>; + status = "okay"; + 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)>; + 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"; + }; + }; +}; + +&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/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/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/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 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..a54967e22de1f --- /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 RP2_PINCTRL_GPIO_FUNC_XIP 0 +#define RP2_PINCTRL_GPIO_FUNC_SPI 1 +#define RP2_PINCTRL_GPIO_FUNC_UART 2 +#define RP2_PINCTRL_GPIO_FUNC_I2C 3 +#define RP2_PINCTRL_GPIO_FUNC_PWM 4 +#define RP2_PINCTRL_GPIO_FUNC_SIO 5 +#define RP2_PINCTRL_GPIO_FUNC_PIO0 6 +#define RP2_PINCTRL_GPIO_FUNC_PIO1 7 +#define RP2_PINCTRL_GPIO_FUNC_GPCK 8 +#define RP2_PINCTRL_GPIO_FUNC_USB 9 +#define RP2_PINCTRL_GPIO_FUNC_NULL 0xf + +#define RP2_ALT_FUNC_POS 0 +#define RP2_ALT_FUNC_MASK 0xf + +#define RP2_PIN_NUM_POS 4 +#define RP2_PIN_NUM_MASK 0x1f + +#define RP2040_PINMUX(pin_num, alt_func) (pin_num << RP2_PIN_NUM_POS | \ + alt_func << RP2_ALT_FUNC_POS) + +#define UART0_TX_P0 RP2040_PINMUX(0, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P1 RP2040_PINMUX(1, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_CTS_P2 RP2040_PINMUX(2, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_RTS_P3 RP2040_PINMUX(3, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P4 RP2040_PINMUX(4, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P5 RP2040_PINMUX(5, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P6 RP2040_PINMUX(6, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P7 RP2040_PINMUX(7, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P8 RP2040_PINMUX(8, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P9 RP2040_PINMUX(9, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P10 RP2040_PINMUX(10, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P11 RP2040_PINMUX(11, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_TX_P12 RP2040_PINMUX(12, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P13 RP2040_PINMUX(13, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_CTS_P14 RP2040_PINMUX(14, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_RTS_P15 RP2040_PINMUX(15, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_TX_P16 RP2040_PINMUX(16, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P17 RP2040_PINMUX(17, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_CTS_P18 RP2040_PINMUX(18, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_RTS_P19 RP2040_PINMUX(19, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P20 RP2040_PINMUX(20, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P21 RP2040_PINMUX(21, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P22 RP2040_PINMUX(22, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P23 RP2040_PINMUX(23, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_TX_P24 RP2040_PINMUX(24, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RX_P25 RP2040_PINMUX(25, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_CTS_P26 RP2040_PINMUX(26, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART1_RTS_P27 RP2040_PINMUX(27, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_TX_P28 RP2040_PINMUX(28, RP2_PINCTRL_GPIO_FUNC_UART) +#define UART0_RX_P29 RP2040_PINMUX(29, RP2_PINCTRL_GPIO_FUNC_UART) + +#endif /* __RP2040_PINCTRL_H__ */ diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt new file mode 100644 index 0000000000000..5df7a48660f82 --- /dev/null +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: Apache-2.0 + +include(ExternalProject) + +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) + + # The Second Stage Bootloader is only linked to the app that resides + # at 0x100. Therefore, only if the app's offset is 0x100, the second + # stage bootloader should be compiled. + if(CONFIG_RP2_REQUIRES_SECOND_STAGE_BOOT) + foreach(flash W25Q080 GENERIC_03H IS25LP080 W25X10CL AT25SF128A) + if(CONFIG_RP2_FLASH_${flash}) + set(flash_type ${flash}) + break() + endif() + endforeach() + + set(rp2_bootloader_prefix ${CMAKE_BINARY_DIR}/bootloader) + ExternalProject_Add( + second_stage_bootloader + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/bootloader + BINARY_DIR ${rp2_bootloader_prefix} + CMAKE_ARGS + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_ASM_COMPILER=${CMAKE_ASM_COMPILER} + -DZEPHYR_HAL_RPI_PICO_MODULE_DIR=${ZEPHYR_HAL_RPI_PICO_MODULE_DIR} + -DZEPHYR_BASE=${ZEPHYR_BASE} + -DFLASH_TYPE=${flash_type} + -DPYTHON_EXECUTABLE=${Python3_EXECUTABLE} + INSTALL_COMMAND "" # No installation needed + BUILD_BYPRODUCTS ${rp2_bootloader_prefix}/boot_stage2.S + BUILD_ALWAYS TRUE + ) + zephyr_library_sources(${rp2_bootloader_prefix}/boot_stage2.S) + endif() + + # 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( + ${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..70cd6ede5351c --- /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/bootloader/CMakeLists.txt b/modules/hal_rpi_pico/bootloader/CMakeLists.txt new file mode 100644 index 0000000000000..172bed0cd0bc3 --- /dev/null +++ b/modules/hal_rpi_pico/bootloader/CMakeLists.txt @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +# Skip compiler checking +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +project(second_stage_bootloader) +enable_language(ASM) + +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) + +add_executable(boot_stage2) + +if(${FLASH_TYPE} STREQUAL W25Q080) + set(flash_type_file boot2_w25q080.S) +elseif(${FLASH_TYPE} STREQUAL GENERIC_03H) + set(flash_type_file boot2_generic_03h.S) +elseif(${FLASH_TYPE} STREQUAL IS25LP080) + set(flash_type_file boot2_is25lp080.S) +elseif(${FLASH_TYPE} STREQUAL W25X10CL) + set(flash_type_file boot2_w25x10cl.S) +elseif(${FLASH_TYPE} STREQUAL AT25SF128A) + set(flash_type_file boot2_at25sf128a.S) +else() + message(FATAL_ERROR "No flash type selected") +endif() + +target_sources(boot_stage2 PRIVATE ${boot_stage_dir}/${flash_type_file}) + +target_include_directories(boot_stage2 PUBLIC + .. + ${boot_stage_dir}/asminclude + ${rp2_common_dir}/pico_platform/include + ${rp2040_dir}/hardware_regs/include + ${common_dir}/pico_base/include + ${ZEPHYR_BASE}/include + ) + +target_link_options(boot_stage2 PRIVATE + "-nostartfiles" + "--specs=nosys.specs" + "LINKER:--script=${boot_stage_dir}/boot_stage2.ld" + ) + +# The second stage bootloader is compiled without kconfig definitions. +# Therefore, in order to use toolchain.h, it needs to define CONFIG_ARM. +target_compile_definitions(boot_stage2 PRIVATE -DCONFIG_ARM=1) + +# Generates a binary file from the compiled bootloader +add_custom_command(TARGET boot_stage2 + POST_BUILD + BYPRODUCTS boot_stage2.bin + COMMAND ${CMAKE_OBJCOPY} -Obinary $ boot_stage2.bin + ) + +# Checksums the binary, pads it, and generates an assembly file +add_custom_command(TARGET boot_stage2 + POST_BUILD + BYPRODUCTS boot_stage2.S + COMMAND ${PYTHON_EXECUTABLE} ${boot_stage_dir}/pad_checksum + -s 0xffffffff boot_stage2.bin boot_stage2.S + ) 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..4cb7452e19ef9 --- /dev/null +++ b/modules/hal_rpi_pico/pico/config_autogen.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Originally this file is generated by pico-sdk, and some files + * try to include it. Therefore, we have to provide that file, + * with this exact name. + * Since this file ends up included in all pico-sdk code, it's + * used to inject workarounds to make pico-sdk compile with Zephyr. + */ + +#ifndef _CONFIG_AUTOGEN_H_ +#define _CONFIG_AUTOGEN_H_ + +/* WORKAROUNDS */ + +/* + * static_assert is not supported, so BUILD_ASSERT is used instead. + * BUILD_ASSERT is included through toolchain.h. + */ +#include +#define static_assert(expr, msg...) BUILD_ASSERT((expr), "" msg) + +/* Convert uses of asm, which is not supported in c99, to __asm */ +#define asm __asm + +/* Disable binary info */ +#define PICO_NO_BINARY_INFO 1 + +/* Zephyr compatible way of forcing inline */ +#ifndef __always_inline +#define __always_inline ALWAYS_INLINE +#endif /* __always_inline */ + +#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/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 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..468d4545c5b23 --- /dev/null +++ b/soc/arm/rpi_pico/Kconfig.defconfig @@ -0,0 +1,13 @@ +# 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" + +config PINCTRL + default y + +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..210f5623ae986 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(soc.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..0470f2aaa69c1 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/Kconfig.defconfig.rp2040 @@ -0,0 +1,14 @@ +# # Raspberry Pi RP2040 MCU + +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "rp2040" + depends on SOC_RP2040 + +config BUILD_OUTPUT_UF2_USE_FLASH_BASE + default y if RP2_REQUIRES_SECOND_STAGE_BOOT + +config BUILD_OUTPUT_UF2_USE_FLASH_OFFSET + default y if !RP2_REQUIRES_SECOND_STAGE_BOOT 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..b13942234d436 --- /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..601182672db46 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/Kconfig.soc @@ -0,0 +1,50 @@ +# 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 + +config RP2_REQUIRES_SECOND_STAGE_BOOT + bool + default y if FLASH_LOAD_OFFSET = 0x100 + +# Flash type used by the SoC. The board should select the one used. + +config RP2_FLASH_W25Q080 + bool + help + Configure RP2 to use a W25Q080 flash chip, or similar. Should be selected + by the board definition, not the user. + +config RP2_FLASH_GENERIC_03H + bool + help + Configure RP2 to use a flash chip supporting the standard 03h command. + Should be selected by the board definition, not the user. + +config RP2_FLASH_IS25LP080 + bool + help + Configure RP2 to use a IS25LP080 flash chip, or similar. Should be selected + by the board definition, not the user. + +config RP2_FLASH_W25X10CL + bool + help + Configure RP2 to use a W25X10CL flash chip, or similar. Should be selected + by the board definition, not the user. + +config RP2_FLASH_AT25SF128A + bool + help + Configure RP2 to use a AT25SF128A flash chip, or similar. Should be selected + by the board definition, not the user. diff --git a/soc/arm/rpi_pico/rp2/linker.ld b/soc/arm/rpi_pico/rp2/linker.ld new file mode 100644 index 0000000000000..319f9c29b9c3a --- /dev/null +++ b/soc/arm/rpi_pico/rp2/linker.ld @@ -0,0 +1,29 @@ +/* linker.ld - Linker command/script file */ + +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * Copyright (c) 2021 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * The Second Stage Bootloader is only linked to the app that + * resides at 0x100. This can be the application, or a bootloader + * such as mcuboot. + */ +#if CONFIG_RP2_REQUIRES_SECOND_STAGE_BOOT +MEMORY +{ + BOOT_FLASH (r) : ORIGIN = 0x10000000, LENGTH = 256 +} + +SECTIONS +{ + .boot2 : { + KEEP(*(.boot2)) + } > BOOT_FLASH +} +#endif /* CONFIG_RP2_REQUIRES_SECOND_STAGE_BOOT */ + +#include 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..b6bcc40da1223 --- /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) >> RP2_PIN_NUM_POS) & RP2_PIN_NUM_MASK) +#define RP2_GET_PIN_ALT_FUNC(pinctrl) \ + (((pinctrl) >> RP2_ALT_FUNC_POS) & RP2_ALT_FUNC_MASK) + +#endif /* ZEPHYR_SOC_ARM_RPI_PICO_RP2_PINCTRL_SOC_H_ */ diff --git a/soc/arm/rpi_pico/rp2/soc.c b/soc/arm/rpi_pico/rp2/soc.c new file mode 100644 index 0000000000000..233b09f7e6db0 --- /dev/null +++ b/soc/arm/rpi_pico/rp2/soc.c @@ -0,0 +1,64 @@ +/* + * 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 + +#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); + +static int rp2040_init(const struct device *arg) +{ + uint32_t key; + + 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); + + 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(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..dc47618334ebf --- /dev/null +++ b/soc/arm/rpi_pico/rp2/soc.h @@ -0,0 +1,20 @@ +/* + * 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_ + +#include + +#define __VTOR_PRESENT CONFIG_CPU_CORTEX_M_HAS_VTOR +#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU + +#endif /* _RPI_PICO_RP2040_SOC_H_ */ diff --git a/west.yml b/west.yml index 965ad8b0d8332..3973914af3c1b 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: 191f5ba46fda49523cdaaef27583d1c875ba2c36 + groups: + - hal - name: hal_silabs revision: be39d4eebeddac6e18e9c0c3ba1b31ad1e82eaed path: modules/hal/silabs