summaryrefslogtreecommitdiff
path: root/platforms/chibios
diff options
context:
space:
mode:
authorStefan Kerkmann <karlk90@pm.me>2022-06-30 13:19:27 +0200
committerGitHub <noreply@github.com>2022-06-30 13:19:27 +0200
commitd7173967087e022d20d1f9c812b1b668e9d3f71b (patch)
tree68198271dd5125193795c399c6478ead0a71b09f /platforms/chibios
parentd206c1791e5858323cff0664f39f95edc1381ac5 (diff)
[Core] Add Raspberry Pi RP2040 support (#14877)
* Disable RESET keycode because of naming conflicts * Add Pico SDK as submodule * Add RP2040 build support to QMK * Adjust USB endpoint structs for RP2040 * Add RP2040 bootloader and double-tap reset routine * Add generic and pro micro RP2040 boards * Add RP2040 onekey keyboard * Add WS2812 PIO DMA enabled driver and documentation Supports regular and open-drain output configuration. RP2040 GPIOs are sadly not 5V tolerant, so this is a bit use-less or needs extra hardware or you take the risk to fry your hardware. * Adjust SIO Driver for RP2040 * Adjust I2C Driver for RP2040 * Adjust SPI Driver for RP2040 * Add PIO serial driver and documentation * Add general RP2040 documentation * Apply suggestions from code review Co-authored-by: Nick Brassel <nick@tzarc.org> Co-authored-by: Nick Brassel <nick@tzarc.org>
Diffstat (limited to 'platforms/chibios')
-rw-r--r--platforms/chibios/_pin_defs.h5
-rw-r--r--platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk9
-rw-r--r--platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h12
-rw-r--r--platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h13
-rw-r--r--platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h62
-rw-r--r--platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h98
-rw-r--r--platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk9
-rw-r--r--platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h12
-rw-r--r--platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h13
-rw-r--r--platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h98
-rw-r--r--platforms/chibios/bootloaders/rp2040.c57
-rw-r--r--platforms/chibios/chibios_config.h21
-rw-r--r--platforms/chibios/drivers/serial_usart.c28
-rw-r--r--platforms/chibios/drivers/spi_master.c31
-rw-r--r--platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c457
-rw-r--r--platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c189
-rw-r--r--platforms/chibios/flash.mk2
-rw-r--r--platforms/chibios/platform.mk15
-rw-r--r--platforms/chibios/vendors/RP/RP2040.mk285
-rw-r--r--platforms/chibios/vendors/RP/_pin_defs.h37
-rw-r--r--platforms/chibios/vendors/RP/pico_sdk_shims.c9
-rw-r--r--platforms/chibios/vendors/RP/stage2_bootloaders.c174
22 files changed, 1628 insertions, 8 deletions
diff --git a/platforms/chibios/_pin_defs.h b/platforms/chibios/_pin_defs.h
index 0d96e2fc3b..414c9e3d11 100644
--- a/platforms/chibios/_pin_defs.h
+++ b/platforms/chibios/_pin_defs.h
@@ -21,6 +21,11 @@
# include <hal.h>
#endif
+/* Include the vendor specific pin defs */
+#if __has_include_next("_pin_defs.h")
+# include_next "_pin_defs.h"
+#endif
+
#define A0 PAL_LINE(GPIOA, 0)
#define A1 PAL_LINE(GPIOA, 1)
#define A2 PAL_LINE(GPIOA, 2)
diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk
new file mode 100644
index 0000000000..911cc5a058
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk
@@ -0,0 +1,9 @@
+# List of all the board related files.
+BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c
+
+# Required include directories
+BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC += $(BOARDINC)
diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h
new file mode 100644
index 0000000000..b4363595d0
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h
@@ -0,0 +1,12 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include_next "board.h"
+
+#undef BOARD_RP_PICO_RP2040
+#define BOARD_GENERIC_PROMICRO_RP2040
+
+#undef BOARD_NAME
+#define BOARD_NAME "Pro Micro RP2040"
diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h
new file mode 100644
index 0000000000..d53f57edd9
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h
@@ -0,0 +1,13 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define CH_CFG_SMP_MODE TRUE
+#define CH_CFG_ST_RESOLUTION 32
+#define CH_CFG_ST_FREQUENCY 1000000
+#define CH_CFG_INTERVALS_SIZE 32
+#define CH_CFG_TIME_TYPES_SIZE 32
+#define CH_CFG_ST_TIMEDELTA 20
+
+#include_next <chconf.h>
diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h
new file mode 100644
index 0000000000..7fe9b654e1
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h
@@ -0,0 +1,62 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+/**======================
+ ** I2C Driver
+ *========================**/
+
+#if !defined(I2C_DRIVER)
+# define I2C_DRIVER I2CD2
+#endif
+
+#if !defined(I2C1_SDA_PIN)
+# define I2C1_SDA_PIN GP2
+#endif
+
+#if !defined(I2C1_SCL_PIN)
+# define I2C1_SCL_PIN GP3
+#endif
+
+/**======================
+ ** SPI Driver
+ *========================**/
+
+#if !defined(SPI_DRIVER)
+# define SPI_DRIVER SPID0
+#endif
+
+#if !defined(SPI_SCK_PIN)
+# define SPI_SCK_PIN GP18
+#endif
+
+#if !defined(SPI_MISO_PIN)
+# define SPI_MISO_PIN GP20
+#endif
+
+#if !defined(SPI_MOSI_PIN)
+# define SPI_MOSI_PIN GP19
+#endif
+
+/**======================
+ ** SERIAL Driver
+ *========================**/
+
+#if !defined(SERIAL_USART_DRIVER)
+# define SERIAL_USART_DRIVER SIOD0
+#endif
+
+#if !defined(SERIAL_USART_TX_PIN) && !defined(SOFT_SERIAL_PIN)
+# define SERIAL_USART_TX_PIN GP0
+#endif
+
+#if !defined(SERIAL_USART_RX_PIN)
+# define SERIAL_USART_RX_PIN GP1
+#endif
+
+/**======================
+ ** Double-tap
+ *========================**/
+
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET
diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h
new file mode 100644
index 0000000000..8348e5312f
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h
@@ -0,0 +1,98 @@
+/*
+ ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef MCUCONF_H
+#define MCUCONF_H
+
+/*
+ * RP2040_MCUCONF drivers configuration.
+ *
+ * IRQ priorities:
+ * 3...0 Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...1 Lowest...Highest.
+ */
+
+#define RP2040_MCUCONF
+
+/*
+ * HAL driver system settings.
+ */
+#define RP_NO_INIT FALSE
+#define RP_CORE1_START FALSE
+#define RP_CORE1_VECTORS_TABLE _vectors
+#define RP_CORE1_ENTRY_POINT _crt0_c1_entry
+#define RP_CORE1_STACK_END __c1_main_stack_end__
+
+/*
+ * IRQ system settings.
+ */
+#define RP_IRQ_SYSTICK_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM0_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM1_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM2_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM3_PRIORITY 2
+#define RP_IRQ_UART0_PRIORITY 3
+#define RP_IRQ_UART1_PRIORITY 3
+#define RP_IRQ_SPI0_PRIORITY 2
+#define RP_IRQ_SPI1_PRIORITY 2
+#define RP_IRQ_USB0_PRIORITY 3
+#define RP_IRQ_I2C0_PRIORITY 2
+#define RP_IRQ_I2C1_PRIORITY 2
+
+/*
+ * ADC driver system settings.
+ */
+#define RP_ADC_USE_ADC1 FALSE
+
+/*
+ * SIO driver system settings.
+ */
+#define RP_SIO_USE_UART0 TRUE
+#define RP_SIO_USE_UART1 FALSE
+
+/*
+ * SPI driver system settings.
+ */
+#define RP_SPI_USE_SPI0 TRUE
+#define RP_SPI_USE_SPI1 FALSE
+#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI0_DMA_PRIORITY 1
+#define RP_SPI_SPI1_DMA_PRIORITY 1
+#define RP_SPI_DMA_ERROR_HOOK(spip)
+
+/*
+ * I2C driver system settings.
+ */
+#define RP_I2C_USE_I2C0 FALSE
+#define RP_I2C_USE_I2C1 TRUE
+#define RP_I2C_BUSY_TIMEOUT 50
+#define RP_I2C_ADDRESS_MODE_10BIT FALSE
+
+/*
+ * USB driver system settings.
+ */
+#define RP_USB_USE_USBD0 TRUE
+#define RP_USB_FORCE_VBUS_DETECT TRUE
+#define RP_USE_EXTERNAL_VBUS_DETECT FALSE
+#define RP_USB_USE_SOF_INTR TRUE
+#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE
+
+#endif /* MCUCONF_H */
diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk
new file mode 100644
index 0000000000..911cc5a058
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk
@@ -0,0 +1,9 @@
+# List of all the board related files.
+BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c
+
+# Required include directories
+BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC += $(BOARDINC)
diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h
new file mode 100644
index 0000000000..052050c944
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h
@@ -0,0 +1,12 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include_next "board.h"
+
+#undef BOARD_RP_PICO_RP2040
+#define BOARD_GENERIC_RP2040
+
+#undef BOARD_NAME
+#define BOARD_NAME "Generic Raspberry Pi RP2040"
diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h
new file mode 100644
index 0000000000..d53f57edd9
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h
@@ -0,0 +1,13 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define CH_CFG_SMP_MODE TRUE
+#define CH_CFG_ST_RESOLUTION 32
+#define CH_CFG_ST_FREQUENCY 1000000
+#define CH_CFG_INTERVALS_SIZE 32
+#define CH_CFG_TIME_TYPES_SIZE 32
+#define CH_CFG_ST_TIMEDELTA 20
+
+#include_next <chconf.h>
diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h
new file mode 100644
index 0000000000..9d8dc61aac
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h
@@ -0,0 +1,98 @@
+/*
+ ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef MCUCONF_H
+#define MCUCONF_H
+
+/*
+ * RP2040_MCUCONF drivers configuration.
+ *
+ * IRQ priorities:
+ * 3...0 Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...1 Lowest...Highest.
+ */
+
+#define RP2040_MCUCONF
+
+/*
+ * HAL driver system settings.
+ */
+#define RP_NO_INIT FALSE
+#define RP_CORE1_START FALSE
+#define RP_CORE1_VECTORS_TABLE _vectors
+#define RP_CORE1_ENTRY_POINT _crt0_c1_entry
+#define RP_CORE1_STACK_END __c1_main_stack_end__
+
+/*
+ * IRQ system settings.
+ */
+#define RP_IRQ_SYSTICK_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM0_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM1_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM2_PRIORITY 2
+#define RP_IRQ_TIMER_ALARM3_PRIORITY 2
+#define RP_IRQ_UART0_PRIORITY 3
+#define RP_IRQ_UART1_PRIORITY 3
+#define RP_IRQ_SPI0_PRIORITY 2
+#define RP_IRQ_SPI1_PRIORITY 2
+#define RP_IRQ_USB0_PRIORITY 3
+#define RP_IRQ_I2C0_PRIORITY 2
+#define RP_IRQ_I2C1_PRIORITY 2
+
+/*
+ * ADC driver system settings.
+ */
+#define RP_ADC_USE_ADC1 FALSE
+
+/*
+ * SIO driver system settings.
+ */
+#define RP_SIO_USE_UART0 FALSE
+#define RP_SIO_USE_UART1 FALSE
+
+/*
+ * SPI driver system settings.
+ */
+#define RP_SPI_USE_SPI0 FALSE
+#define RP_SPI_USE_SPI1 FALSE
+#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
+#define RP_SPI_SPI0_DMA_PRIORITY 1
+#define RP_SPI_SPI1_DMA_PRIORITY 1
+#define RP_SPI_DMA_ERROR_HOOK(spip)
+
+/*
+ * I2C driver system settings.
+ */
+#define RP_I2C_USE_I2C0 FALSE
+#define RP_I2C_USE_I2C1 FALSE
+#define RP_I2C_BUSY_TIMEOUT 50
+#define RP_I2C_ADDRESS_MODE_10BIT FALSE
+
+/*
+ * USB driver system settings.
+ */
+#define RP_USB_USE_USBD0 TRUE
+#define RP_USB_FORCE_VBUS_DETECT TRUE
+#define RP_USE_EXTERNAL_VBUS_DETECT FALSE
+#define RP_USB_USE_SOF_INTR TRUE
+#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE
+
+#endif /* MCUCONF_H */
diff --git a/platforms/chibios/bootloaders/rp2040.c b/platforms/chibios/bootloaders/rp2040.c
new file mode 100644
index 0000000000..13a54036ef
--- /dev/null
+++ b/platforms/chibios/bootloaders/rp2040.c
@@ -0,0 +1,57 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "quantum.h"
+#include "hal.h"
+#include "bootloader.h"
+#include "pico/bootrom.h"
+
+#if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED)
+# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK 0U
+#else
+# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK (1U << RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED)
+#endif
+
+__attribute__((weak)) void mcu_reset(void) {
+ NVIC_SystemReset();
+}
+void bootloader_jump(void) {
+ reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U);
+}
+
+void enter_bootloader_mode_if_requested(void) {}
+
+#if defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET)
+# if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT)
+# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 200U
+# endif
+
+// Needs to be located in a RAM section that is never initialized on boot to
+// preserve its value on reset
+static volatile uint32_t __attribute__((section(".ram0.bootloader_magic"))) magic_location;
+const uint32_t magic_token = 0xCAFEB0BA;
+
+// We can not use the __early_init / enter_bootloader_mode_if_requested hook as
+// we depend on an already initialized system with usable memory regions and
+// populated function pointer tables to the optimized math functions in the
+// bootrom. This function is called just prior to main.
+void __late_init(void) {
+ // All clocks have to be enabled before jumping to the bootloader function,
+ // otherwise the bootrom will be stuck infinitely.
+ clocks_init();
+
+ if (magic_location != magic_token) {
+ magic_location = magic_token;
+ // ChibiOS is not initialized at this point, so sleeping is only
+ // possible via busy waiting. The internal timer peripheral is running
+ // at this point with a precision of 1us.
+ chSysPolledDelayX(MS2RTC(1 * MHZ, RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT));
+ magic_location = 0;
+ return;
+ }
+
+ magic_location = 0;
+ reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U);
+}
+
+#endif
diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h
index a7098f2713..1571bd5cd3 100644
--- a/platforms/chibios/chibios_config.h
+++ b/platforms/chibios/chibios_config.h
@@ -19,6 +19,27 @@
# define SPLIT_USB_DETECT // Force this on when dedicated pin is not used
#endif
+#if defined(MCU_RP)
+# define CPU_CLOCK RP_CORE_CLK
+
+# define USE_GPIOV1
+# define PAL_OUTPUT_TYPE_OPENDRAIN _Static_assert(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible");
+
+# define usb_lld_endpoint_fields
+
+# define I2C1_SCL_PAL_MODE (PAL_MODE_ALTERNATE_I2C | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_PUE | PAL_RP_PAD_DRIVE4)
+# define I2C1_SDA_PAL_MODE I2C1_SCL_PAL_MODE
+
+# define USE_I2CV1_CONTRIB
+# if !defined(I2C1_CLOCK_SPEED)
+# define I2C1_CLOCK_SPEED 400000
+# endif
+
+# define SPI_SCK_PAL_MODE (PAL_MODE_ALTERNATE_SPI | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_DRIVE4)
+# define SPI_MOSI_PAL_MODE SPI_SCK_PAL_MODE
+# define SPI_MISO_PAL_MODE SPI_SCK_PAL_MODE
+#endif
+
// STM32 compatibility
#if defined(MCU_STM32)
# define CPU_CLOCK STM32_SYSCLK
diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c
index f76afb5db4..6581a5b6e9 100644
--- a/platforms/chibios/drivers/serial_usart.c
+++ b/platforms/chibios/drivers/serial_usart.c
@@ -8,12 +8,12 @@
#if defined(SERIAL_USART_CONFIG)
static QMKSerialConfig serial_config = SERIAL_USART_CONFIG;
-#else
+#elif defined(MCU_STM32) /* STM32 MCUs */
static QMKSerialConfig serial_config = {
# if HAL_USE_SERIAL
- .speed = (SERIAL_USART_SPEED), /* baudrate - mandatory */
+ .speed = (SERIAL_USART_SPEED),
# else
- .baud = (SERIAL_USART_SPEED), /* baudrate - mandatory */
+ .baud = (SERIAL_USART_SPEED),
# endif
.cr1 = (SERIAL_USART_CR1),
.cr2 = (SERIAL_USART_CR2),
@@ -23,6 +23,19 @@ static QMKSerialConfig serial_config = {
.cr3 = (SERIAL_USART_CR3)
# endif
};
+#elif defined(MCU_RP) /* Raspberry Pi MCUs */
+/* USART in 8E2 config with RX and TX FIFOs enabled. */
+// clang-format off
+static QMKSerialConfig serial_config = {
+ .baud = (SERIAL_USART_SPEED),
+ .UARTLCR_H = UART_UARTLCR_H_WLEN_8BITS | UART_UARTLCR_H_PEN | UART_UARTLCR_H_STP2 | UART_UARTLCR_H_FEN,
+ .UARTCR = 0U,
+ .UARTIFLS = UART_UARTIFLS_RXIFLSEL_1_8F | UART_UARTIFLS_TXIFLSEL_1_8E,
+ .UARTDMACR = 0U
+};
+// clang-format on
+#else
+# error MCU Familiy not supported by default, supply your own serial_config by defining SERIAL_USART_CONFIG in your keyboard files.
#endif
static QMKSerialDriver* serial_driver = (QMKSerialDriver*)&SERIAL_USART_DRIVER;
@@ -156,7 +169,7 @@ inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t
* @brief Initiate pins for USART peripheral. Half-duplex configuration.
*/
__attribute__((weak)) void usart_init(void) {
-# if defined(MCU_STM32)
+# if defined(MCU_STM32) /* STM32 MCUs */
# if defined(USE_GPIOV1)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
# else
@@ -166,6 +179,8 @@ __attribute__((weak)) void usart_init(void) {
# if defined(USART_REMAP)
USART_REMAP;
# endif
+# elif defined(MCU_RP) /* Raspberry Pi MCUs */
+# error Half-duplex with the SIO driver is not supported due to hardware limitations on the RP2040, switch to the PIO driver which has half-duplex support.
# else
# pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files."
# endif
@@ -177,7 +192,7 @@ __attribute__((weak)) void usart_init(void) {
* @brief Initiate pins for USART peripheral. Full-duplex configuration.
*/
__attribute__((weak)) void usart_init(void) {
-# if defined(MCU_STM32)
+# if defined(MCU_STM32) /* STM32 MCUs */
# if defined(USE_GPIOV1)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);
@@ -189,6 +204,9 @@ __attribute__((weak)) void usart_init(void) {
# if defined(USART_REMAP)
USART_REMAP;
# endif
+# elif defined(MCU_RP) /* Raspberry Pi MCUs */
+ palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_UART);
+ palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE_UART);
# else
# pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files."
# endif
diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c
index ce69e7f0ac..f9974d9f6b 100644
--- a/platforms/chibios/drivers/spi_master.c
+++ b/platforms/chibios/drivers/spi_master.c
@@ -20,7 +20,7 @@
static pin_t currentSlavePin = NO_PIN;
-#if defined(K20x) || defined(KL2x)
+#if defined(K20x) || defined(KL2x) || defined(RP2040)
static SPIConfig spiConfig = {NULL, 0, 0, 0};
#else
static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
@@ -167,7 +167,36 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spiConfig.SPI_CPOL = SPI_CPOL_High;
break;
}
+#elif defined(MCU_RP)
+ if (lsbFirst) {
+ osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
+ }
+
+ // Motorola frame format and 8bit transfer data size.
+ spiConfig.SSPCR0 = SPI_SSPCR0_FRF_MOTOROLA | SPI_SSPCR0_DSS_8BIT;
+ // Serial output clock = (ck_sys or ck_peri) / (SSPCPSR->CPSDVSR * (1 +
+ // SSPCR0->SCR)). SCR is always set to zero, as QMK SPI API expects the
+ // passed divisor to be the only value to divide the input clock by.
+ spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254
+ switch (mode) {
+ case 0:
+ spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
+ spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
+ break;
+ case 1:
+ spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
+ spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
+ break;
+ case 2:
+ spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high
+ spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
+ break;
+ case 3:
+ spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high
+ spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
+ break;
+ }
#else
spiConfig.cr1 = 0;
diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c
new file mode 100644
index 0000000000..949fc6dd93
--- /dev/null
+++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c
@@ -0,0 +1,457 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "quantum.h"
+#include "serial_usart.h"
+#include "serial_protocol.h"
+#include "hardware/pio.h"
+#include "hardware/clocks.h"
+
+#if !defined(MCU_RP)
+# error PIO Driver is only available for Raspberry Pi 2040 MCUs!
+#endif
+
+static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout);
+static inline bool send_impl(const uint8_t* source, const size_t size);
+static inline void pio_serve_interrupt(void);
+
+#define MSG_PIO_ERROR ((msg_t)(-3))
+
+#if defined(SERIAL_PIO_USE_PIO1)
+static const PIO pio = pio1;
+
+OSAL_IRQ_HANDLER(RP_PIO1_IRQ_0_HANDLER) {
+ OSAL_IRQ_PROLOGUE();
+ pio_serve_interrupt();
+ OSAL_IRQ_EPILOGUE();
+}
+#else
+static const PIO pio = pio0;
+
+OSAL_IRQ_HANDLER(RP_PIO0_IRQ_0_HANDLER) {
+ OSAL_IRQ_PROLOGUE();
+ pio_serve_interrupt();
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#define UART_TX_WRAP_TARGET 0
+#define UART_TX_WRAP 3
+
+// clang-format off
+#if defined(SERIAL_USART_FULL_DUPLEX)
+static const uint16_t uart_tx_program_instructions[] = {
+ // .wrap_target
+ 0x9fa0, // 0: pull block side 1 [7]
+ 0xf727, // 1: set x, 7 side 0 [7]
+ 0x6001, // 2: out pins, 1
+ 0x0642, // 3: jmp x--, 2 [6]
+ // .wrap
+};
+#else
+static const uint16_t uart_tx_program_instructions[] = {
+ // .wrap_target
+ 0x9fa0, // 0: pull block side 1 [7]
+ 0xf727, // 1: set x, 7 side 0 [7]
+ 0x6081, // 2: out pindirs, 1
+ 0x0642, // 3: jmp x--, 2 [6]
+ // .wrap
+};
+#endif
+// clang-format on
+
+static const pio_program_t uart_tx_program = {
+ .instructions = uart_tx_program_instructions,
+ .length = 4,
+ .origin = -1,
+};
+
+#define UART_RX_WRAP_TARGET 0
+#define UART_RX_WRAP 8
+
+// clang-format off
+static const uint16_t uart_rx_program_instructions[] = {
+ // .wrap_target
+ 0x2020, // 0: wait 0 pin, 0
+ 0xea27, // 1: set x, 7 [10]
+ 0x4001, // 2: in pins, 1
+ 0x0642, // 3: jmp x--, 2 [6]
+ 0x00c8, // 4: jmp pin, 8
+ 0xc020, // 5: irq wait 0
+ 0x20a0, // 6: wait 1 pin, 0
+ 0x0000, // 7: jmp 0
+ 0x8020, // 8: push block
+ // .wrap
+};
+// clang-format on
+
+static const pio_program_t uart_rx_program = {
+ .instructions = uart_rx_program_instructions,
+ .length = 9,
+ .origin = -1,
+};
+
+thread_reference_t rx_thread = NULL;
+static int rx_state_machine = -1;
+
+thread_reference_t tx_thread = NULL;
+static int tx_state_machine = -1;
+
+void pio_serve_interrupt(void) {
+ uint32_t irqs = pio->ints0;
+
+ // The RX FIFO is not empty any more, therefore wake any sleeping rx thread
+ if (irqs & (PIO_IRQ0_INTF_SM0_RXNEMPTY_BITS << rx_state_machine)) {
+ // Disable rx not empty interrupt
+ pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, false);
+
+ osalSysLockFromISR();
+ osalThreadResumeI(&rx_thread, MSG_OK);
+ osalSysUnlockFromISR();
+ }
+
+ // The TX FIFO is not full any more, therefore wake any sleeping tx thread
+ if (irqs & (PIO_IRQ0_INTF_SM0_TXNFULL_BITS << tx_state_machine)) {
+ // Disable tx not full interrupt
+ pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, false);
+ osalSysLockFromISR();
+ osalThreadResumeI(&tx_thread, MSG_OK);
+ osalSysUnlockFromISR();
+ }
+
+ // IRQ 0 is set on framing or break errors by the rx state machine
+ if (pio_interrupt_get(pio, 0UL)) {
+ pio_interrupt_clear(pio, 0UL);
+
+ osalSysLockFromISR();
+ osalThreadResumeI(&rx_thread, MSG_PIO_ERROR);
+ osalSysUnlockFromISR();
+ }
+}
+
+#if !defined(SERIAL_USART_FULL_DUPLEX)
+// The internal pull-ups of the RP2040 are rather weakish with a range of 50k to
+// 80k, which in turn do not provide enough current to guarantee fast signal rise
+// times with a parasitic capacitance of greater than 100pf. In real world
+// applications, like split keyboards which might have vias in the signal path
+// or long PCB traces, this prevents a successful communication. The solution
+// is to temporarily augment the weak pull ups from the receiving side by
+// driving the tx pin high. On the receiving side the lowest possible drive
+// strength is chosen because the transmitting side must still be able to drive
+// the signal low. With this configuration the rise times are fast enough and
+// the generated low level with 360mV will generate a logical zero.
+static inline void enter_rx_state(void) {
+ osalSysLock();
+ // Wait for the transmitting state machines FIFO to run empty. At this point
+ // the last byte has been pulled from the transmitting state machines FIFO
+ // into the output shift register. We have to wait a tiny bit more until
+ // this byte is transmitted, before we can turn on the receiving state
+ // machine again.
+ while (!pio_sm_is_tx_fifo_empty(pio, tx_state_machine)) {
+ }
+ // Wait for ~11 bits, 1 start bit + 8 data bits + 1 stop bit + 1 bit
+ // headroom.
+ chSysPolledDelayX(US2RTC(1 * MHZ, (1000000U * 11 / SERIAL_USART_SPEED)));
+ // Disable tx state machine to not interfere with our tx pin manipulation
+ pio_sm_set_enabled(pio, tx_state_machine, false);
+ gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_2MA);
+ pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << SERIAL_USART_TX_PIN, 1U << SERIAL_USART_TX_PIN);
+ pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, false);
+ pio_sm_set_enabled(pio, rx_state_machine, true);
+ osalSysUnlock();
+}
+
+static inline void leave_rx_state(void) {
+ osalSysLock();
+ // In Half-duplex operation the tx pin dual-functions as sender and
+ // receiver. To not receive the data we will send, we disable the receiving
+ // state machine.
+ pio_sm_set_enabled(pio, rx_state_machine, false);
+ pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, true);
+ pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U, 1U << SERIAL_USART_TX_PIN);
+ gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_12MA);
+ pio_sm_restart(pio, tx_state_machine);
+ pio_sm_set_enabled(pio, tx_state_machine, true);
+ osalSysUnlock();
+}
+#else
+// All this trickery is gladly not necessary for full-duplex.
+static inline void enter_rx_state(void) {}
+static inline void leave_rx_state(void) {}
+#endif
+
+/**
+ * @brief Clear the RX and TX hardware FIFOs of the state machines.
+ */
+inline void serial_transport_driver_clear(void) {
+ osalSysLock();
+ pio_sm_clear_fifos(pio, rx_state_machine);
+ pio_sm_clear_fifos(pio, tx_state_machine);
+ osalSysUnlock();
+}
+
+static inline msg_t sync_tx(sysinterval_t timeout) {
+ msg_t msg = MSG_OK;
+ osalSysLock();
+ while (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) {
+ pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true);
+ msg = osalThreadSuspendTimeoutS(&tx_thread, timeout);
+ if (msg < MSG_OK) {
+ break;
+ }
+ }
+ osalSysUnlock();
+ return msg;
+}
+
+static inline bool send_impl(const uint8_t* source, const size_t size) {
+ size_t send = 0;
+ msg_t msg;
+ while (send < size) {
+ msg = sync_tx(TIME_MS2I(SERIAL_USART_TIMEOUT));
+ if (msg < MSG_OK) {
+ return false;
+ }
+
+ osalSysLock();
+ while (send < size) {
+ if (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) {
+ break;
+ }
+ if (send >= size) {
+ break;
+ }
+ pio_sm_put(pio, tx_state_machine, (uint32_t)(*source));
+ source++;
+ send++;
+ }
+ osalSysUnlock();
+ }
+
+ return send == size;
+}
+
+/**
+ * @brief Blocking send of buffer with timeout.
+ *
+ * @return true Send success.
+ * @return false Send failed.
+ */
+inline bool serial_transport_send(const uint8_t* source, const size_t size) {
+ leave_rx_state();
+ bool result = send_impl(source, size);
+ enter_rx_state();
+
+ return result;
+}
+
+static inline msg_t sync_rx(sysinterval_t timeout) {
+ msg_t msg = MSG_OK;
+ osalSysLock();
+ while (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) {
+ pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true);
+ msg = osalThreadSuspendTimeoutS(&rx_thread, timeout);
+ if (msg < MSG_OK) {
+ break;
+ }
+ }
+ osalSysUnlock();
+ return msg;
+}
+
+static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout) {
+ size_t read = 0U;
+
+ while (read < size) {
+ msg_t msg = sync_rx(timeout);
+ if (msg < MSG_OK) {
+ return false;
+ }
+ osalSysLock();
+ while (true) {
+ if (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) {
+ break;
+ }
+ if (read >= size) {
+ break;
+ }
+ *destination++ = *((uint8_t*)&pio->rxf[rx_state_machine] + 3U);
+ read++;
+ }
+ osalSysUnlock();
+ }
+
+ return read == size;
+}
+
+/**
+ * @brief Blocking receive of size * bytes with timeout.
+ *
+ * @return true Receive success.
+ * @return false Receive failed, e.g. by timeout.
+ */
+inline bool serial_transport_receive(uint8_t* destination, const size_t size) {
+ return receive_impl(destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT));
+}
+
+/**
+ * @brief Blocking receive of size * bytes.
+ *
+ * @return true Receive success.
+ * @return false Receive failed.
+ */
+inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t size) {
+ return receive_impl(destination, size, TIME_INFINITE);
+}
+
+static inline void pio_tx_init(pin_t tx_pin) {
+ uint pio_idx = pio_get_index(pio);
+ uint offset = pio_add_program(pio, &uart_tx_program);
+
+#if defined(SERIAL_USART_FULL_DUPLEX)
+ // clang-format off
+ iomode_t tx_pin_mode = PAL_RP_GPIO_OE |
+ PAL_RP_PAD_SLEWFAST |
+ PAL_RP_PAD_DRIVE4 |
+ (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
+ // clang-format on
+ pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << tx_pin, 1U << tx_pin);
+ pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true);
+#else
+ // clang-format off
+ iomode_t tx_pin_mode = PAL_RP_PAD_IE |
+ PAL_RP_GPIO_OE |
+ PAL_RP_PAD_SCHMITT |
+ PAL_RP_PAD_PUE |
+ PAL_RP_PAD_SLEWFAST |
+ PAL_RP_PAD_DRIVE12 |
+ PAL_RP_IOCTRL_OEOVER_DRVINVPERI |
+ (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
+ // clang-format on
+ pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U << tx_pin, 1U << tx_pin);
+ pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true);
+#endif
+
+ palSetLineMode(tx_pin, tx_pin_mode);
+
+ pio_sm_config config = pio_get_default_sm_config();
+ sm_config_set_wrap(&config, offset + UART_TX_WRAP_TARGET, offset + UART_TX_WRAP);
+#if defined(SERIAL_USART_FULL_DUPLEX)
+ sm_config_set_sideset(&config, 2, true, false);
+#else
+ sm_config_set_sideset(&config, 2, true, true);
+#endif
+ // OUT shifts to right, no autopull
+ sm_config_set_out_shift(&config, true, false, 32);
+ // We are mapping both OUT and side-set to the same pin, because sometimes
+ // we need to assert user data onto the pin (with OUT) and sometimes
+ // assert constant values (start/stop bit)
+ sm_config_set_out_pins(&config, tx_pin, 1);
+ sm_config_set_sideset_pins(&config, tx_pin);
+ // We only need TX, so get an 8-deep FIFO!
+ sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX);
+ // SM transmits 1 bit per 8 execution cycles.
+ float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED);
+ sm_config_set_clkdiv(&config, div);
+ pio_sm_init(pio, tx_state_machine, offset, &config);
+ pio_sm_set_enabled(pio, tx_state_machine, true);
+}
+
+static inline void pio_rx_init(pin_t rx_pin) {
+ uint offset = pio_add_program(pio, &uart_rx_program);
+
+#if defined(SERIAL_USART_FULL_DUPLEX)
+ uint pio_idx = pio_get_index(pio);
+ pio_sm_set_consecutive_pindirs(pio, rx_state_machine, rx_pin, 1, false);
+ // clang-format off
+ iomode_t rx_pin_mode = PAL_RP_PAD_IE |
+ PAL_RP_PAD_SCHMITT |
+ PAL_RP_PAD_PUE |
+ (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
+ // clang-format on
+ palSetLineMode(rx_pin, rx_pin_mode);
+#endif
+
+ pio_sm_config config = pio_get_default_sm_config();
+ sm_config_set_wrap(&config, offset + UART_RX_WRAP_TARGET, offset + UART_RX_WRAP);
+ sm_config_set_in_pins(&config, rx_pin); // for WAIT, IN
+ sm_config_set_jmp_pin(&config, rx_pin); // for JMP
+ // Shift to right, autopush disabled
+ sm_config_set_in_shift(&config, true, false, 32);
+ // Deeper FIFO as we're not doing any TX
+ sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX);
+ // SM transmits 1 bit per 8 execution cycles.
+ float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED);
+ sm_config_set_clkdiv(&config, div);
+ pio_sm_init(pio, rx_state_machine, offset, &config);
+ pio_sm_set_enabled(pio, rx_state_machine, true);
+}
+
+static inline void pio_init(pin_t tx_pin, pin_t rx_pin) {
+ uint pio_idx = pio_get_index(pio);
+
+ /* Get PIOx peripheral out of reset state. */
+ hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1);
+
+ tx_state_machine = pio_claim_unused_sm(pio, true);
+ if (tx_state_machine < 0) {
+ dprintln("ERROR: Failed to acquire state machine for serial transmission!");
+ return;
+ }
+ pio_tx_init(tx_pin);
+
+ rx_state_machine = pio_claim_unused_sm(pio, true);
+ if (rx_state_machine < 0) {
+ dprintln("ERROR: Failed to acquire state machine for serial reception!");
+ return;
+ }
+ pio_rx_init(rx_pin);
+
+ // Enable error flag IRQ source for rx state machine
+ pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true);
+ pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true);
+ pio_set_irq0_source_enabled(pio, pis_interrupt0, true);
+
+ // Enable PIO specific interrupt vector
+#if defined(SERIAL_PIO_USE_PIO1)
+ nvicEnableVector(RP_PIO1_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY);
+#else
+ nvicEnableVector(RP_PIO0_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY);
+#endif
+
+ enter_rx_state();
+}
+
+/**
+ * @brief PIO driver specific initialization function for the master side.
+ */
+void serial_transport_driver_master_init(void) {
+#if defined(SERIAL_USART_FULL_DUPLEX)
+ pin_t tx_pin = SERIAL_USART_TX_PIN;
+ pin_t rx_pin = SERIAL_USART_RX_PIN;
+#else
+ pin_t tx_pin = SERIAL_USART_TX_PIN;
+ pin_t rx_pin = SERIAL_USART_TX_PIN;
+#endif
+
+#if defined(SERIAL_USART_PIN_SWAP)
+ pio_init(rx_pin, tx_pin);
+#else
+ pio_init(tx_pin, rx_pin);
+#endif
+}
+
+/**
+ * @brief PIO driver specific initialization function for the slave side.
+ */
+void serial_transport_driver_slave_init(void) {
+#if defined(SERIAL_USART_FULL_DUPLEX)
+ pin_t tx_pin = SERIAL_USART_TX_PIN;
+ pin_t rx_pin = SERIAL_USART_RX_PIN;
+#else
+ pin_t tx_pin = SERIAL_USART_TX_PIN;
+ pin_t rx_pin = SERIAL_USART_TX_PIN;
+#endif
+
+ pio_init(tx_pin, rx_pin);
+}
diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c
new file mode 100644
index 0000000000..bc34eded14
--- /dev/null
+++ b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c
@@ -0,0 +1,189 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "quantum.h"
+#include "ws2812.h"
+#include "hardware/pio.h"
+#include "hardware/clocks.h"
+
+#if !defined(MCU_RP)
+# error PIO Driver is only available for Raspberry Pi 2040 MCUs!
+#endif
+
+#if defined(WS2812_PIO_USE_PIO1)
+static const PIO pio = pio1;
+#else
+static const PIO pio = pio0;
+#endif
+
+#if !defined(RP_DMA_PRIORITY_WS2812)
+# define RP_DMA_PRIORITY_WS2812 12
+#endif
+
+static int state_machine = -1;
+
+#define WS2812_WRAP_TARGET 0
+#define WS2812_WRAP 3
+
+#define WS2812_T1 2
+#define WS2812_T2 5
+#define WS2812_T3 3
+
+#if defined(WS2812_EXTERNAL_PULLUP)
+
+# pragma message "The GPIOs of the RP2040 are NOT 5V tolerant! Make sure to NOT apply any voltage over 3.3V to the RGB data pin."
+
+// clang-format off
+static const uint16_t ws2812_program_instructions[] = {
+ // .wrap_target
+ 0x7221, // 0: out x, 1 side 1 [2]
+ 0x0123, // 1: jmp !x, 3 side 0 [1]
+ 0x0400, // 2: jmp 0 side 0 [4]
+ 0xb442, // 3: nop side 1 [4]
+ // .wrap
+};
+
+#else
+
+static const uint16_t ws2812_program_instructions[] = {
+ // .wrap_target
+ 0x6221, // 0: out x, 1 side 0 [2]
+ 0x1123, // 1: jmp !x, 3 side 1 [1]
+ 0x1400, // 2: jmp 0 side 1 [4]
+ 0xa442, // 3: nop side 0 [4]
+ // .wrap
+};
+// clang-format on
+#endif
+
+static const pio_program_t ws2812_program = {
+ .instructions = ws2812_program_instructions,
+ .length = 4,
+ .origin = -1,
+};
+
+static uint32_t WS2812_BUFFER[RGBLED_NUM];
+static const rp_dma_channel_t* WS2812_DMA_CHANNEL;
+
+bool ws2812_init(void) {
+ uint pio_idx = pio_get_index(pio);
+ /* Get PIOx peripheral out of reset state. */
+ hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1);
+
+ // clang-format off
+ iomode_t rgb_pin_mode = PAL_RP_PAD_SLEWFAST |
+ PAL_RP_GPIO_OE |
+ (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
+ // clang-format on
+
+ palSetLineMode(RGB_DI_PIN, rgb_pin_mode);
+
+ state_machine = pio_claim_unused_sm(pio, true);
+ if (state_machine < 0) {
+ dprintln("ERROR: Failed to acquire state machine for WS2812 output!");
+ return false;
+ }
+
+ uint offset = pio_add_program(pio, &ws2812_program);
+
+ pio_sm_set_consecutive_pindirs(pio, state_machine, RGB_DI_PIN, 1, true);
+
+ pio_sm_config config = pio_get_default_sm_config();
+ sm_config_set_wrap(&config, offset + WS2812_WRAP_TARGET, offset + WS2812_WRAP);
+ sm_config_set_sideset_pins(&config, RGB_DI_PIN);
+ sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX);
+
+#if defined(WS2812_EXTERNAL_PULLUP)
+ /* Instruct side-set to change the pin-directions instead of outputting
+ * a logic level. We generate our levels the following way:
+ *
+ * 1: Set RGB data pin to high impedance input and let the pull-up drive the
+ * signal high.
+ *
+ * 0: Set RGB data pin to low impedance output and drive the pin low.
+ */
+ sm_config_set_sideset(&config, 1, false, true);
+#else
+ sm_config_set_sideset(&config, 1, false, false);
+#endif
+
+#if defined(RGBW)
+ sm_config_set_out_shift(&config, false, true, 32);
+#else
+ sm_config_set_out_shift(&config, false, true, 24);
+#endif
+
+ int cycles_per_bit = WS2812_T1 + WS2812_T2 + WS2812_T3;
+ float div = clock_get_hz(clk_sys) / (800.0f * KHZ * cycles_per_bit);
+ sm_config_set_clkdiv(&config, div);
+
+ pio_sm_init(pio, state_machine, offset, &config);
+ pio_sm_set_enabled(pio, state_machine, true);
+
+ WS2812_DMA_CHANNEL = dmaChannelAlloc(RP_DMA_CHANNEL_ID_ANY, RP_DMA_PRIORITY_WS2812, NULL, NULL);
+
+ // clang-format off
+ uint32_t mode = DMA_CTRL_TRIG_INCR_READ |
+ DMA_CTRL_TRIG_DATA_SIZE_WORD |
+ DMA_CTRL_TRIG_IRQ_QUIET |
+ DMA_CTRL_TRIG_TREQ_SEL(pio_idx == 0 ? state_machine : state_machine + 8);
+ // clang-format on
+
+ dmaChannelSetModeX(WS2812_DMA_CHANNEL, mode);
+ dmaChannelSetDestinationX(WS2812_DMA_CHANNEL, (uint32_t)&pio->txf[state_machine]);
+ return true;
+}
+
+/**
+ * @brief Convert RGBW value into WS2812 compatible 32-bit data word.
+ */
+__always_inline static uint32_t rgbw8888_to_u32(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
+#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
+ return ((uint32_t)green << 24) | ((uint32_t)red << 16) | ((uint32_t)blue << 8) | ((uint32_t)white);
+#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
+ return ((uint32_t)red << 24) | ((uint32_t)green << 16) | ((uint32_t)blue << 8) | ((uint32_t)white);
+#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
+ return ((uint32_t)blue << 24) | ((uint32_t)green << 16) | ((uint32_t)red << 8) | ((uint32_t)white);
+#endif
+}
+
+static inline void sync_ws2812_transfer(void) {
+ if (unlikely(dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine))) {
+ fast_timer_t start = timer_read_fast();
+ do {
+ // Abort the synchronization if we have to wait longer than the total
+ // count of LEDs in millisecounds. This is safely much longer than it
+ // would take to push all the data out.
+ if (unlikely(timer_elapsed_fast(start) > RGBLED_NUM)) {
+ dprintln("ERROR: WS2812 DMA transfer has stalled, aborting!");
+ dmaChannelDisableX(WS2812_DMA_CHANNEL);
+ return;
+ }
+
+ } while (dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine));
+ // We wait for the WS2812 chain to reset after all data has been pushed
+ // out.
+ wait_us(WS2812_TRST_US);
+ }
+}
+
+void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
+ static bool is_initialized = false;
+ if (unlikely(!is_initialized)) {
+ is_initialized = ws2812_init();
+ }
+
+ sync_ws2812_transfer();
+
+ for (int i = 0; i < leds; i++) {
+#if defined(RGBW)
+ WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, ledarray[i].w);
+#else
+ WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, 0);
+#endif
+ }
+
+ dmaChannelSetSourceX(WS2812_DMA_CHANNEL, (uint32_t)WS2812_BUFFER);
+ dmaChannelSetCounterX(WS2812_DMA_CHANNEL, leds);
+ dmaChannelEnableX(WS2812_DMA_CHANNEL);
+}
diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk
index 86bbc22943..790c4f3316 100644
--- a/platforms/chibios/flash.mk
+++ b/platforms/chibios/flash.mk
@@ -108,6 +108,8 @@ else ifeq ($(strip $(BOOTLOADER)),kiibohd)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
else ifeq ($(strip $(BOOTLOADER)),tinyuf2)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY)
+else ifeq ($(strip $(BOOTLOADER)),rp2040)
+ $(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY)
else ifeq ($(strip $(MCU_FAMILY)),KINETIS)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY)
else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062)
diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk
index 72428a762f..32b8c5a946 100644
--- a/platforms/chibios/platform.mk
+++ b/platforms/chibios/platform.mk
@@ -88,9 +88,9 @@ ifeq ("$(MCU_PORT_NAME)","")
endif
ifeq ("$(wildcard $(PLATFORM_MK))","")
- PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
+ PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
ifeq ("$(wildcard $(PLATFORM_MK))","")
- PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
+ PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
endif
endif
@@ -288,6 +288,17 @@ EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \
$(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH)
#
+# QMK specific MCU family support selection.
+##############################################################################
+ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk)","")
+ # Either by MCU series e.g. STM32/STM32F1xx.mk or...
+ include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk
+else ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk)","")
+ # By MCU family e.g. STM32/STM32.mk
+ include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk
+endif
+
+#
# ChibiOS-Contrib
##############################################################################
diff --git a/platforms/chibios/vendors/RP/RP2040.mk b/platforms/chibios/vendors/RP/RP2040.mk
new file mode 100644
index 0000000000..1aa925cb15
--- /dev/null
+++ b/platforms/chibios/vendors/RP/RP2040.mk
@@ -0,0 +1,285 @@
+#
+# Raspberry Pi RP2040 specific drivers
+##############################################################################
+COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/vendor/$(MCU_FAMILY)/$(MCU_SERIES)
+
+ifeq ($(strip $(WS2812_DRIVER)), vendor)
+ OPT_DEFS += -DRP_DMA_REQUIRED=TRUE
+endif
+
+#
+# Raspberry Pi Pico SDK Support
+##############################################################################
+ADEFS += -DCRT0_VTOR_INIT=1 \
+ -DCRT0_EXTRA_CORES_NUMBER=0
+
+CFLAGS += -DPICO_NO_FPGA_CHECK \
+ -DNDEBUG
+
+#
+# Pico SDK source and header files needed by QMK and ChibiOS
+##############################################################################
+PICOSDKROOT := $(TOP_DIR)/lib/pico-sdk
+
+PICOSDKSRC = $(PICOSDKROOT)/src/rp2_common/hardware_clocks/clocks.c \
+ $(PICOSDKROOT)/src/rp2_common/hardware_pll/pll.c \
+ $(PICOSDKROOT)/src/rp2_common/hardware_pio/pio.c \
+ $(PICOSDKROOT)/src/rp2_common/hardware_gpio/gpio.c \
+ $(PICOSDKROOT)/src/rp2_common/hardware_claim/claim.c \
+ $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/watchdog.c \
+ $(PICOSDKROOT)/src/rp2_common/hardware_xosc/xosc.c \
+ $(PICOSDKROOT)/src/rp2_common/pico_bootrom/bootrom.c
+
+PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \
+ $(PICOSDKROOT)/src/common/pico_base/include \
+ $(PICOSDKROOT)/src/rp2_common/pico_platform/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_base/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_clocks/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_claim/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_gpio/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_irq/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_pll/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_pio/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_sync/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_resets/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_xosc/include \
+ $(PICOSDKROOT)/src/rp2040/hardware_regs/include \
+ $(PICOSDKROOT)/src/rp2040/hardware_structs/include \
+ $(PICOSDKROOT)/src/boards/include \
+ $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include
+
+PLATFORM_SRC += $(PICOSDKSRC)
+EXTRAINCDIRS += $(PICOSDKINC)
+
+PLATFORM_RP2040_PATH := $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)
+
+PLATFORM_SRC += $(PLATFORM_RP2040_PATH)/stage2_bootloaders.c \
+ $(PLATFORM_RP2040_PATH)/pico_sdk_shims.c
+
+EXTRAINCDIRS += $(PLATFORM_RP2040_PATH)
+
+#
+# RP2040 optimized compiler intrinsics
+##############################################################################
+
+# Enables optimized Compiler intrinsics which are located in the RP2040
+# bootrom. This needs startup code and linker script support from ChibiOS,
+# which is WIP. Therefore disabled by default for now.
+RP2040_INTRINSICS_ENABLED ?= no
+ifeq ($(strip $(RP2040_INTRINSICS_ENABLED)), yes)
+ PICOSDKINTRINSICSSRC = $(PICOSDKROOT)/src/rp2_common/pico_float/float_aeabi.S \
+ $(PICOSDKROOT)/src/rp2_common/pico_float/float_math.c \
+ $(PICOSDKROOT)/src/rp2_common/pico_float/float_init_rom.c \
+ $(PICOSDKROOT)/src/rp2_common/pico_float/float_v1_rom_shim.S \
+ $(PICOSDKROOT)/src/rp2_common/pico_double/double_aeabi.S \
+ $(PICOSDKROOT)/src/rp2_common/pico_double/double_math.c \
+ $(PICOSDKROOT)/src/rp2_common/pico_double/double_init_rom.c \
+ $(PICOSDKROOT)/src/rp2_common/pico_double/double_v1_rom_shim.S \
+ $(PICOSDKROOT)/src/rp2_common/pico_divider/divider.S \
+ $(PICOSDKROOT)/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S \
+ $(PICOSDKROOT)/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S \
+ $(PICOSDKROOT)/src/rp2_common/pico_malloc/pico_malloc.c \
+ $(PICOSDKROOT)/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
+
+ PICOSDKINTRINSICSINC = $(PICOSDKROOT)/src/common/pico_base/include \
+ $(PICOSDKROOT)/src/rp2_common/pico_platfrom/include \
+ $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include \
+ $(PICOSDKROOT)/src/rp2_common/hardware_divider/include \
+ $(PICOSDKROOT)/src/rp2_common/pico_float/include \
+ $(PICOSDKROOT)/src/rp2_common/pico_double/include \
+ $(PICOSDKROOT)/src/rp2_common/pico_malloc/include
+
+ OPT_DEFS += -DPICO_FLOAT_SUPPORT_ROM_V1=0 -DPICO_DOUBLE_SUPPORT_ROM_V1=0
+
+ CFLAGS += -Wl,--defsym=__StackLimit=__heap_end__
+ CFLAGS += -Wl,--defsym=__unhandled_user_irq=_unhandled_exception
+ CFLAGS += -Wl,--build-id=none
+
+ # single precision floating point intrinsics
+ OPT_DEFS += -DPICO_FLOAT_IN_RAM=1
+ OPT_DEFS += -DPICO_FLOAT_PROPAGATE_NANS=0
+
+ CFLAGS += -Wl,--wrap=__aeabi_fdiv
+ CFLAGS += -Wl,--wrap=__aeabi_fmul
+ CFLAGS += -Wl,--wrap=__aeabi_frsub
+ CFLAGS += -Wl,--wrap=__aeabi_fsub
+ CFLAGS += -Wl,--wrap=__aeabi_cfcmpeq
+ CFLAGS += -Wl,--wrap=__aeabi_cfrcmple
+ CFLAGS += -Wl,--wrap=__aeabi_cfcmple
+ CFLAGS += -Wl,--wrap=__aeabi_fcmpeq
+ CFLAGS += -Wl,--wrap=__aeabi_fcmplt
+ CFLAGS += -Wl,--wrap=__aeabi_fcmple
+ CFLAGS += -Wl,--wrap=__aeabi_fcmpge
+ CFLAGS += -Wl,--wrap=__aeabi_fcmpgt
+ CFLAGS += -Wl,--wrap=__aeabi_fcmpun
+ CFLAGS += -Wl,--wrap=__aeabi_i2f
+ CFLAGS += -Wl,--wrap=__aeabi_l2f
+ CFLAGS += -Wl,--wrap=__aeabi_ui2f
+ CFLAGS += -Wl,--wrap=__aeabi_ul2f
+ CFLAGS += -Wl,--wrap=__aeabi_i2f
+ CFLAGS += -Wl,--wrap=__aeabi_f2iz
+ CFLAGS += -Wl,--wrap=__aeabi_f2lz
+ CFLAGS += -Wl,--wrap=__aeabi_f2uiz
+ CFLAGS += -Wl,--wrap=__aeabi_f2ulz
+ CFLAGS += -Wl,--wrap=__aeabi_f2d
+ CFLAGS += -Wl,--wrap=sqrtf
+ CFLAGS += -Wl,--wrap=cosf
+ CFLAGS += -Wl,--wrap=sinf
+ CFLAGS += -Wl,--wrap=tanf
+ CFLAGS += -Wl,--wrap=atan2f
+ CFLAGS += -Wl,--wrap=expf
+ CFLAGS += -Wl,--wrap=logf
+ CFLAGS += -Wl,--wrap=ldexpf
+ CFLAGS += -Wl,--wrap=copysignf
+ CFLAGS += -Wl,--wrap=truncf
+ CFLAGS += -Wl,--wrap=floorf
+ CFLAGS += -Wl,--wrap=ceilf
+ CFLAGS += -Wl,--wrap=roundf
+ CFLAGS += -Wl,--wrap=sincosf
+ CFLAGS += -Wl,--wrap=asinf
+ CFLAGS += -Wl,--wrap=acosf
+ CFLAGS += -Wl,--wrap=atanf
+ CFLAGS += -Wl,--wrap=sinhf
+ CFLAGS += -Wl,--wrap=coshf
+ CFLAGS += -Wl,--wrap=tanhf
+ CFLAGS += -Wl,--wrap=asinhf
+ CFLAGS += -Wl,--wrap=acoshf
+ CFLAGS += -Wl,--wrap=atanhf
+ CFLAGS += -Wl,--wrap=exp2f
+ CFLAGS += -Wl,--wrap=log2f
+ CFLAGS += -Wl,--wrap=exp10f
+ CFLAGS += -Wl,--wrap=log10f
+ CFLAGS += -Wl,--wrap=powf
+ CFLAGS += -Wl,--wrap=powintf
+ CFLAGS += -Wl,--wrap=hypotf
+ CFLAGS += -Wl,--wrap=cbrtf
+ CFLAGS += -Wl,--wrap=fmodf
+ CFLAGS += -Wl,--wrap=dremf
+ CFLAGS += -Wl,--wrap=remainderf
+ CFLAGS += -Wl,--wrap=remquof
+ CFLAGS += -Wl,--wrap=expm1f
+ CFLAGS += -Wl,--wrap=log1pf
+ CFLAGS += -Wl,--wrap=fmaf
+
+ # double precision floating point intrinsics
+ OPT_DEFS += -DPICO_DOUBLE_IN_RAM=1
+ OPT_DEFS += -DPICO_DOUBLE_PROPAGATE_NANS=0
+
+ CFLAGS += -Wl,--wrap=__aeabi_dadd
+ CFLAGS += -Wl,--wrap=__aeabi_ddiv
+ CFLAGS += -Wl,--wrap=__aeabi_dmul
+ CFLAGS += -Wl,--wrap=__aeabi_drsub
+ CFLAGS += -Wl,--wrap=__aeabi_dsub
+ CFLAGS += -Wl,--wrap=__aeabi_cdcmpeq
+ CFLAGS += -Wl,--wrap=__aeabi_cdrcmple
+ CFLAGS += -Wl,--wrap=__aeabi_cdcmple
+ CFLAGS += -Wl,--wrap=__aeabi_dcmpeq
+ CFLAGS += -Wl,--wrap=__aeabi_dcmplt
+ CFLAGS += -Wl,--wrap=__aeabi_dcmple
+ CFLAGS += -Wl,--wrap=__aeabi_dcmpge
+ CFLAGS += -Wl,--wrap=__aeabi_dcmpgt
+ CFLAGS += -Wl,--wrap=__aeabi_dcmpun
+ CFLAGS += -Wl,--wrap=__aeabi_i2d
+ CFLAGS += -Wl,--wrap=__aeabi_l2d
+ CFLAGS += -Wl,--wrap=__aeabi_ui2d
+ CFLAGS += -Wl,--wrap=__aeabi_ul2d
+ CFLAGS += -Wl,--wrap=__aeabi_d2iz
+ CFLAGS += -Wl,--wrap=__aeabi_d2lz
+ CFLAGS += -Wl,--wrap=__aeabi_d2uiz
+ CFLAGS += -Wl,--wrap=__aeabi_d2ulz
+ CFLAGS += -Wl,--wrap=__aeabi_d2f
+ CFLAGS += -Wl,--wrap=sqrt
+ CFLAGS += -Wl,--wrap=cos
+ CFLAGS += -Wl,--wrap=sin
+ CFLAGS += -Wl,--wrap=tan
+ CFLAGS += -Wl,--wrap=atan2
+ CFLAGS += -Wl,--wrap=exp
+ CFLAGS += -Wl,--wrap=log
+ CFLAGS += -Wl,--wrap=ldexp
+ CFLAGS += -Wl,--wrap=copysign
+ CFLAGS += -Wl,--wrap=trunc
+ CFLAGS += -Wl,--wrap=floor
+ CFLAGS += -Wl,--wrap=ceil
+ CFLAGS += -Wl,--wrap=round
+ CFLAGS += -Wl,--wrap=sincos
+ CFLAGS += -Wl,--wrap=asin
+ CFLAGS += -Wl,--wrap=acos
+ CFLAGS += -Wl,--wrap=atan
+ CFLAGS += -Wl,--wrap=sinh
+ CFLAGS += -Wl,--wrap=cosh
+ CFLAGS += -Wl,--wrap=tanh
+ CFLAGS += -Wl,--wrap=asinh
+ CFLAGS += -Wl,--wrap=acosh
+ CFLAGS += -Wl,--wrap=atanh
+ CFLAGS += -Wl,--wrap=exp2
+ CFLAGS += -Wl,--wrap=log2
+ CFLAGS += -Wl,--wrap=exp10
+ CFLAGS += -Wl,--wrap=log10
+ CFLAGS += -Wl,--wrap=pow
+ CFLAGS += -Wl,--wrap=powint
+ CFLAGS += -Wl,--wrap=hypot
+ CFLAGS += -Wl,--wrap=cbrt
+ CFLAGS += -Wl,--wrap=fmod
+ CFLAGS += -Wl,--wrap=drem
+ CFLAGS += -Wl,--wrap=remainder
+ CFLAGS += -Wl,--wrap=remquo
+ CFLAGS += -Wl,--wrap=expm1
+ CFLAGS += -Wl,--wrap=log1p
+ CFLAGS += -Wl,--wrap=fma
+
+ # bit operation intrinsics
+ OPT_DEFS += -DPICO_BITS_IN_RAM=1
+
+ CFLAGS += -Wl,--wrap=__clzsi2
+ CFLAGS += -Wl,--wrap=__clzsi2
+ CFLAGS += -Wl,--wrap=__clzdi2
+ CFLAGS += -Wl,--wrap=__ctzsi2
+ CFLAGS += -Wl,--wrap=__ctzdi2
+ CFLAGS += -Wl,--wrap=__popcountsi2
+ CFLAGS += -Wl,--wrap=__popcountdi2
+ CFLAGS += -Wl,--wrap=__clz
+ CFLAGS += -Wl,--wrap=__clzl
+ CFLAGS += -Wl,--wrap=__clzsi2
+ CFLAGS += -Wl,--wrap=__clzll
+
+ # integer division intrinsics
+ OPT_DEFS += -DPICO_DIVIDER_IN_RAM=1
+ OPT_DEFS += -DPICO_DIVIDER_DISABLE_INTERRUPTS=1
+
+ CFLAGS += -Wl,--wrap=__aeabi_idiv
+ CFLAGS += -Wl,--wrap=__aeabi_idivmod
+ CFLAGS += -Wl,--wrap=__aeabi_ldivmod
+ CFLAGS += -Wl,--wrap=__aeabi_uidiv
+ CFLAGS += -Wl,--wrap=__aeabi_uidivmod
+ CFLAGS += -Wl,--wrap=__aeabi_uldivmod
+
+ # 64bit integer intrinsics
+ OPT_DEFS += -DPICO_INT64_OPS_IN_RAM=1
+
+ CFLAGS += -Wl,--wrap=__aeabi_lmul
+
+ # malloc and friends functions
+ OPT_DEFS += -DPICO_USE_MALLOC_MUTEX=0
+ OPT_DEFS += -DPICO_DEBUG_MALLOC=0
+ OPT_DEFS ?= -DPICO_MALLOC_PANIC=0
+
+ CFLAGS += -Wl,--wrap=malloc
+ CFLAGS += -Wl,--wrap=calloc
+ CFLAGS += -Wl,--wrap=free
+
+ # memory operation intrinsics
+ OPT_DEFS += -DPICO_MEM_IN_RAM=1
+
+ CFLAGS += -Wl,--wrap=memcpy
+ CFLAGS += -Wl,--wrap=memset
+ CFLAGS += -Wl,--wrap=__aeabi_memcpy
+ CFLAGS += -Wl,--wrap=__aeabi_memset
+ CFLAGS += -Wl,--wrap=__aeabi_memcpy4
+ CFLAGS += -Wl,--wrap=__aeabi_memset4
+ CFLAGS += -Wl,--wrap=__aeabi_memcpy8
+ CFLAGS += -Wl,--wrap=__aeabi_memset8
+
+ PLATFORM_SRC += $(PICOSDKINTRINSICSSRC)
+ EXTRAINCDIRS += $(PICOSDKINTRINSICSINC)
+endif
diff --git a/platforms/chibios/vendors/RP/_pin_defs.h b/platforms/chibios/vendors/RP/_pin_defs.h
new file mode 100644
index 0000000000..4241845369
--- /dev/null
+++ b/platforms/chibios/vendors/RP/_pin_defs.h
@@ -0,0 +1,37 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+/* RP2040 GPIO Numbering */
+#define GP0 0U
+#define GP1 1U
+#define GP2 2U
+#define GP3 3U
+#define GP4 4U
+#define GP5 5U
+#define GP6 6U
+#define GP7 7U
+#define GP8 8U
+#define GP9 9U
+#define GP10 10U
+#define GP11 11U
+#define GP12 12U
+#define GP13 13U
+#define GP14 14U
+#define GP15 15U
+#define GP16 16U
+#define GP17 17U
+#define GP18 18U
+#define GP19 19U
+#define GP20 20U
+#define GP21 21U
+#define GP22 22U
+#define GP23 23U
+#define GP24 24U
+#define GP25 25U
+#define GP26 26U
+#define GP27 27U
+#define GP28 28U
+#define GP29 29U
+#define GP30 30U
diff --git a/platforms/chibios/vendors/RP/pico_sdk_shims.c b/platforms/chibios/vendors/RP/pico_sdk_shims.c
new file mode 100644
index 0000000000..f6e3943928
--- /dev/null
+++ b/platforms/chibios/vendors/RP/pico_sdk_shims.c
@@ -0,0 +1,9 @@
+// Copyright 2022 Stefan Kerkmann
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <stdbool.h>
+#include <ch.h>
+
+void panic(const char *fmt, ...) {
+ chSysHalt(fmt);
+}
diff --git a/platforms/chibios/vendors/RP/stage2_bootloaders.c b/platforms/chibios/vendors/RP/stage2_bootloaders.c
new file mode 100644
index 0000000000..f22112fca9
--- /dev/null
+++ b/platforms/chibios/vendors/RP/stage2_bootloaders.c
@@ -0,0 +1,174 @@
+// ----------------------------------------------------------------------------
+// Pre-compiled second stage boot code for RP2040.
+//
+// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
+// SPDX-License-Identifier: BSD-3-Clause
+// ----------------------------------------------------------------------------
+
+#include <stdint.h>
+
+#define BOOTLOADER_SECTION __attribute__ ((used, section (".boot2")))
+
+#if defined(RP2040_FLASH_AT25SF128A)
+
+uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = {
+ 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
+ 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b,
+ 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
+ 0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20,
+ 0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21,
+ 0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66,
+ 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e,
+ 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1,
+ 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60,
+ 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21,
+ 0x19, 0x66, 0x20, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21,
+ 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60,
+ 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49,
+ 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5,
+ 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42,
+ 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7,
+ 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00,
+ 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0x20,
+ 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0xdd, 0xc0, 0xb5
+};
+
+#elif defined(RP2040_FLASH_GD25Q64CS)
+
+uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = {
+ 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
+ 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b,
+ 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
+ 0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20,
+ 0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21,
+ 0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66,
+ 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e,
+ 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1,
+ 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60,
+ 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xe7, 0x21,
+ 0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21,
+ 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60,
+ 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49,
+ 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5,
+ 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42,
+ 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7,
+ 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00,
+ 0x21, 0x12, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x10, 0x00, 0xa0,
+ 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe2, 0xd9, 0xa2, 0xb5
+};
+
+#elif defined(RP2040_FLASH_W25X10CL)
+
+uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = {
+ 0x00, 0xb5, 0x14, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
+ 0x12, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x11, 0x49, 0x12, 0x48,
+ 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xbb, 0x21, 0x19, 0x66, 0x02, 0x21,
+ 0x19, 0x66, 0x08, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd0, 0x00, 0x21,
+ 0x99, 0x60, 0x0c, 0x49, 0x0a, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60,
+ 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x08, 0x48, 0x09, 0x49,
+ 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x3f, 0x00, 0x1d, 0x12, 0x00, 0x00,
+ 0xf4, 0x00, 0x00, 0x18, 0x1e, 0x10, 0x00, 0x20, 0x00, 0x01, 0x00, 0x10,
+ 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0x81, 0x53, 0x9a
+};
+
+#elif defined(RP2040_FLASH_IS25LP080)
+
+uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = {
+ 0x00, 0xb5, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
+ 0x29, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x28, 0x48, 0x00, 0xf0,
+ 0x42, 0xf8, 0x28, 0x4a, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, 0x19, 0x66,
+ 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20,
+ 0x1a, 0x66, 0x00, 0xf0, 0x2b, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x1f, 0x48,
+ 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21,
+ 0x99, 0x60, 0x1d, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x1c, 0x49,
+ 0x1c, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66,
+ 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60,
+ 0x17, 0x49, 0x16, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc,
+ 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x14, 0x48, 0x14, 0x49, 0x08, 0x60,
+ 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a,
+ 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1,
+ 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff,
+ 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18,
+ 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x33, 0x43, 0xb2
+};
+
+#elif defined(RP2040_FLASH_GENERIC_03H)
+
+uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = {
+ 0x00, 0xb5, 0x0c, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
+ 0x0a, 0x49, 0x19, 0x60, 0x0a, 0x49, 0x0b, 0x48, 0x01, 0x60, 0x00, 0x21,
+ 0x59, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0,
+ 0x00, 0x47, 0x07, 0x48, 0x07, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3,
+ 0x08, 0x88, 0x08, 0x47, 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x1f, 0x00,
+ 0x18, 0x02, 0x00, 0x03, 0xf4, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x10,
+ 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0xec, 0x21, 0x0d
+};
+
+#else
+
+uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = {
+ 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
+ 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b,
+ 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
+ 0x99, 0x50, 0x2b, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20,
+ 0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21,
+ 0x19, 0x66, 0x00, 0xf0, 0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66,
+ 0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e,
+ 0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21,
+ 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60,
+ 0x00, 0x21, 0x59, 0x60, 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21,
+ 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0,
+ 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60,
+ 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47,
+ 0x12, 0x48, 0x13, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88,
+ 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0,
+ 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66,
+ 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd,
+ 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00,
+ 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18,
+ 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x0b, 0x8f, 0xd5
+};
+
+#endif