diff --git a/src/machine/board_pico2.go b/src/machine/board_pico2.go new file mode 100644 index 0000000000..327c542fbc --- /dev/null +++ b/src/machine/board_pico2.go @@ -0,0 +1,88 @@ +//go:build pico2 + +package machine + +// GPIO pins +const ( + GP0 Pin = GPIO0 + GP1 Pin = GPIO1 + GP2 Pin = GPIO2 + GP3 Pin = GPIO3 + GP4 Pin = GPIO4 + GP5 Pin = GPIO5 + GP6 Pin = GPIO6 + GP7 Pin = GPIO7 + GP8 Pin = GPIO8 + GP9 Pin = GPIO9 + GP10 Pin = GPIO10 + GP11 Pin = GPIO11 + GP12 Pin = GPIO12 + GP13 Pin = GPIO13 + GP14 Pin = GPIO14 + GP15 Pin = GPIO15 + GP16 Pin = GPIO16 + GP17 Pin = GPIO17 + GP18 Pin = GPIO18 + GP19 Pin = GPIO19 + GP20 Pin = GPIO20 + GP21 Pin = GPIO21 + GP22 Pin = GPIO22 + GP26 Pin = GPIO26 + GP27 Pin = GPIO27 + GP28 Pin = GPIO28 + + // Onboard LED + LED Pin = GPIO25 + + // Onboard crystal oscillator frequency, in MHz. + xoscFreq = 12 // MHz +) + +// I2C Default pins on Raspberry Pico. +const ( + I2C0_SDA_PIN = GP4 + I2C0_SCL_PIN = GP5 + + I2C1_SDA_PIN = GP2 + I2C1_SCL_PIN = GP3 +) + +// SPI default pins +const ( + // Default Serial Clock Bus 0 for SPI communications + SPI0_SCK_PIN = GPIO18 + // Default Serial Out Bus 0 for SPI communications + SPI0_SDO_PIN = GPIO19 // Tx + // Default Serial In Bus 0 for SPI communications + SPI0_SDI_PIN = GPIO16 // Rx + + // Default Serial Clock Bus 1 for SPI communications + SPI1_SCK_PIN = GPIO10 + // Default Serial Out Bus 1 for SPI communications + SPI1_SDO_PIN = GPIO11 // Tx + // Default Serial In Bus 1 for SPI communications + SPI1_SDI_PIN = GPIO12 // Rx +) + +// UART pins +const ( + UART0_TX_PIN = GPIO0 + UART0_RX_PIN = GPIO1 + UART1_TX_PIN = GPIO8 + UART1_RX_PIN = GPIO9 + UART_TX_PIN = UART0_TX_PIN + UART_RX_PIN = UART0_RX_PIN +) + +var DefaultUART = UART0 + +// USB identifiers +const ( + usb_STRING_PRODUCT = "Pico2" + usb_STRING_MANUFACTURER = "Raspberry Pi" +) + +var ( + usb_VID uint16 = 0x2E8A + usb_PID uint16 = 0x000A +) diff --git a/src/machine/machine_rp2_2350.go b/src/machine/machine_rp2_2350.go index adb75f0090..90f9e2c3ac 100644 --- a/src/machine/machine_rp2_2350.go +++ b/src/machine/machine_rp2_2350.go @@ -8,10 +8,8 @@ import ( ) const ( - LED = GPIO25 _NUMBANK0_GPIOS = 48 _NUMBANK0_IRQS = 6 - xoscFreq = 12 // Pico 2 Crystal oscillator Abracon ABM8-272-T3 frequency in MHz rp2350ExtraReg = 1 notimpl = "rp2350: not implemented" initUnreset = rp.RESETS_RESET_ADC | @@ -22,16 +20,6 @@ const ( rp.RESETS_RESET_USBCTRL ) -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - const ( PinOutput PinMode = iota PinInput diff --git a/targets/arm.ld b/targets/arm.ld index 39b5c75ddb..cdf5b1dd43 100644 --- a/targets/arm.ld +++ b/targets/arm.ld @@ -9,6 +9,7 @@ SECTIONS .text : { KEEP(*(.isr_vector)) + KEEP(*(.after_isr_vector)) /* for the RP2350 */ *(.text) *(.text.*) *(.rodata) diff --git a/targets/pico2.json b/targets/pico2.json index 13f07e18cb..3c91fa47bd 100644 --- a/targets/pico2.json +++ b/targets/pico2.json @@ -3,8 +3,5 @@ "rp2350" ], "build-tags": ["pico2"], - "linkerscript": "targets/pico2.ld", - "extra-files": [ - "targets/pico_boot_stage2.S" - ] + "serial-port": ["2e8a:000A"] } diff --git a/targets/rp2350.json b/targets/rp2350.json index 0f6e5fb4e9..9070560bcb 100644 --- a/targets/rp2350.json +++ b/targets/rp2350.json @@ -8,9 +8,9 @@ "msd-firmware-name": "firmware.uf2", "binary-format": "uf2", "uf2-family-id": "0xe48bff59","comment":"See page 393 of RP2350 datasheet: RP2350 Arm Secure image (i.e. one intended to be booted directly by the bootrom)", - "rp2040-boot-patch": true, "extra-files": [ - "targets/rp2350_boot2_generic03h.S" + "src/device/rp/rp2350.s", + "targets/rp2350_embedded_block.s" ], "linkerscript": "targets/rp2350.ld", "openocd-interface": "picoprobe", diff --git a/targets/rp2350.ld b/targets/rp2350.ld index 95fe3bbeee..dbe495cf7c 100644 --- a/targets/rp2350.ld +++ b/targets/rp2350.ld @@ -10,9 +10,7 @@ MEMORY i.e: Separate stacks for core0 and core1. */ SRAM4 : ORIGIN = 0x20080000, LENGTH = 4k SRAM5 : ORIGIN = 0x20081000, LENGTH = 4k - /* Reserve exactly 256 bytes at start of flash for second stage bootloader */ - BOOT2_TEXT (rx) : ORIGIN = 0x10000000, LENGTH = 256 - FLASH_TEXT (rx) : ORIGIN = 0x10000000 + 256, LENGTH = 2048k - 256 + FLASH_TEXT (rx) : ORIGIN = 0x10000000, LENGTH = 2048k RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 512k } @@ -20,26 +18,6 @@ _stack_size = 2K; SECTIONS { - /* Second stage bootloader is prepended to the image. It must be 256 bytes - and checksummed. The gap to the checksum is zero-padded. - */ - .boot2 : { - __boot2_start__ = .; - KEEP (*(.boot2)); - - /* Explicitly allocate space for CRC32 checksum at end of second stage - bootloader - */ - . = __boot2_start__ + 256 - 4; - LONG(0) - } > BOOT2_TEXT = 0x0 - - /* The second stage will always enter the image at the start of .text. - The debugger will use the ELF entry point, which is the _entry_point - symbol if present, otherwise defaults to start of .text. - This can be used to transfer control back to the bootrom on debugger - launches only, to perform proper flash setup. - */ } INCLUDE "targets/arm.ld" diff --git a/targets/rp2350_boot2_generic03h.S b/targets/rp2350_boot2_generic03h.S deleted file mode 100644 index 70b861afc4..0000000000 --- a/targets/rp2350_boot2_generic03h.S +++ /dev/null @@ -1,461 +0,0 @@ -// ---------------------------------------------------------------------------- -// Second stage boot code -// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd. -// SPDX-License-Identifier: BSD-3-Clause -// -// Device: Anything which responds to 03h serial read command -// -// Details: * Configure SSI to translate each APB read into a 03h command -// * 8 command clocks, 24 address clocks and 32 data clocks -// * This enables you to boot from almost anything: you can pretty -// much solder a potato to your PCB, or a piece of cheese -// * The tradeoff is performance around 3x worse than QSPI XIP -// -// Building: * This code must be position-independent, and use stack only -// * The code will be padded to a size of 256 bytes, including a -// 4-byte checksum. Therefore code size cannot exceed 252 bytes. -// ---------------------------------------------------------------------------- - -// #include "pico.h" // https://github.com/raspberrypi/pico-sdk/blob/master/src/boards/include/boards/pico.h -// Figure out what boot uses... - -// #include "pico/asm_helper.S" // https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2350/pico_platform/include/pico/asm_helper.S -#if !PICO_ASSEMBLER_IS_CLANG -#define apsr_nzcv r15 -#endif -# note we don't do this by default in this file for backwards comaptibility with user code -# that may include this file, but not use unified syntax. Note that this macro does equivalent -# setup to the pico_default_asm macro for inline assembly in C code. -.macro pico_default_asm_setup -#ifndef __riscv -.syntax unified // Selects Unified Assembly Language (UAL) syntax for assembler. Unifies ARM and thumb into single syntax. -.cpu cortex-m33 // Specify target CPU architecture. -.fpu fpv5-sp-d16 // Specify the type of FPU available on CPU. Supports SP (single precision) operations with 16 double precision registers. -.thumb // Assemble subsequent code with Thumb instruction set, the compact 16-bit encoding of the most frequently used 32-bit ARM instructions. -.section .boot2, "ax" // Defines a new section named .boot2 with attributes 'a': Allocatable-This section occupies space in memory image, and 'x': This section contains executable code. -// Code and data assembled after this point will be placed in .boot2 section. The Linker script can specify where this section should be located in memory, such as at a specific address. -// We need to ensure this code is placed at the very start of flash. See rp2350.ld, .boot2 is placed at 0x10000000 and has max length 256. -// The compiled code cannot exceed 256 bytes! -// One can check contents by compiling and using objdump to visualize the code: -// tinygo build -target=rp2350 -o=rp2350.elf -serial=none examples/blinky1 -// objdump -s -j .boot2 rp2350.elf -#endif -.endm - -.macro regular_func fnname -.global \fnname // Declares fnname as a global symbol. -.type \fnname,%function // Specifies fnname is a type of function. Helps tools understand fnname is executable code, not data. -#ifndef __riscv -.thumb_func // Indicate fnname is a thumb function. -#endif -\fnname: // Mark point of entry for function. -.endm - - -// #include "hardware/platform_defs.h" // https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2350/hardware_regs/include/hardware/platform_defs.h -#ifndef _u -#ifdef __ASSEMBLER__ -#define _u(x) x -#else -#define _u(x) x ## u -#endif -#endif - -// #include "hardware/regs/addressmap.h" https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2350/hardware_regs/include/hardware/regs/addressmap.h -// Register address offsets for atomic RMW aliases -#define REG_ALIAS_RW_BITS (_u(0x0) << _u(12)) -#define REG_ALIAS_XOR_BITS (_u(0x1) << _u(12)) -#define REG_ALIAS_SET_BITS (_u(0x2) << _u(12)) -#define REG_ALIAS_CLR_BITS (_u(0x3) << _u(12)) - -#define ROM_BASE _u(0x00000000) -#define XIP_BASE _u(0x10000000) -#define XIP_SRAM_BASE _u(0x13ffc000) -#define XIP_END _u(0x14000000) -#define XIP_NOCACHE_NOALLOC_BASE _u(0x14000000) -#define XIP_SRAM_END _u(0x14000000) -#define XIP_NOCACHE_NOALLOC_END _u(0x18000000) -#define XIP_MAINTENANCE_BASE _u(0x18000000) -#define XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE _u(0x1c000000) -#define SRAM0_BASE _u(0x20000000) -#define XIP_NOCACHE_NOALLOC_NOTRANSLATE_END _u(0x20000000) -#define SRAM_BASE _u(0x20000000) -#define SRAM_STRIPED_BASE _u(0x20000000) -#define SRAM4_BASE _u(0x20040000) -#define SRAM8_BASE _u(0x20080000) -#define SRAM_STRIPED_END _u(0x20080000) -#define SRAM_SCRATCH_X_BASE _u(0x20080000) -#define SRAM9_BASE _u(0x20081000) -#define SRAM_SCRATCH_Y_BASE _u(0x20081000) -#define SRAM_END _u(0x20082000) -#define SYSINFO_BASE _u(0x40000000) -#define SYSCFG_BASE _u(0x40008000) -#define CLOCKS_BASE _u(0x40010000) -#define PSM_BASE _u(0x40018000) -#define RESETS_BASE _u(0x40020000) -#define IO_BANK0_BASE _u(0x40028000) -#define IO_QSPI_BASE _u(0x40030000) -#define PADS_BANK0_BASE _u(0x40038000) -#define PADS_QSPI_BASE _u(0x40040000) -#define XOSC_BASE _u(0x40048000) -#define PLL_SYS_BASE _u(0x40050000) -#define PLL_USB_BASE _u(0x40058000) -#define ACCESSCTRL_BASE _u(0x40060000) -#define BUSCTRL_BASE _u(0x40068000) -#define UART0_BASE _u(0x40070000) -#define UART1_BASE _u(0x40078000) -#define SPI0_BASE _u(0x40080000) -#define SPI1_BASE _u(0x40088000) -#define I2C0_BASE _u(0x40090000) -#define I2C1_BASE _u(0x40098000) -#define ADC_BASE _u(0x400a0000) -#define PWM_BASE _u(0x400a8000) -#define TIMER0_BASE _u(0x400b0000) -#define TIMER1_BASE _u(0x400b8000) -#define HSTX_CTRL_BASE _u(0x400c0000) -#define XIP_CTRL_BASE _u(0x400c8000) -#define XIP_QMI_BASE _u(0x400d0000) -#define WATCHDOG_BASE _u(0x400d8000) -#define BOOTRAM_BASE _u(0x400e0000) -#define BOOTRAM_END _u(0x400e0400) -#define ROSC_BASE _u(0x400e8000) -#define TRNG_BASE _u(0x400f0000) -#define SHA256_BASE _u(0x400f8000) -#define POWMAN_BASE _u(0x40100000) -#define TICKS_BASE _u(0x40108000) -#define OTP_BASE _u(0x40120000) -#define OTP_DATA_BASE _u(0x40130000) -#define OTP_DATA_RAW_BASE _u(0x40134000) -#define OTP_DATA_GUARDED_BASE _u(0x40138000) -#define OTP_DATA_RAW_GUARDED_BASE _u(0x4013c000) -#define CORESIGHT_PERIPH_BASE _u(0x40140000) -#define CORESIGHT_ROMTABLE_BASE _u(0x40140000) -#define CORESIGHT_AHB_AP_CORE0_BASE _u(0x40142000) -#define CORESIGHT_AHB_AP_CORE1_BASE _u(0x40144000) -#define CORESIGHT_TIMESTAMP_GEN_BASE _u(0x40146000) -#define CORESIGHT_ATB_FUNNEL_BASE _u(0x40147000) -#define CORESIGHT_TPIU_BASE _u(0x40148000) -#define CORESIGHT_CTI_BASE _u(0x40149000) -#define CORESIGHT_APB_AP_RISCV_BASE _u(0x4014a000) -#define DFT_BASE _u(0x40150000) -#define GLITCH_DETECTOR_BASE _u(0x40158000) -#define TBMAN_BASE _u(0x40160000) -#define DMA_BASE _u(0x50000000) -#define USBCTRL_BASE _u(0x50100000) -#define USBCTRL_DPRAM_BASE _u(0x50100000) -#define USBCTRL_REGS_BASE _u(0x50110000) -#define PIO0_BASE _u(0x50200000) -#define PIO1_BASE _u(0x50300000) -#define PIO2_BASE _u(0x50400000) -#define XIP_AUX_BASE _u(0x50500000) -#define HSTX_FIFO_BASE _u(0x50600000) -#define CORESIGHT_TRACE_BASE _u(0x50700000) -#define SIO_BASE _u(0xd0000000) -#define SIO_NONSEC_BASE _u(0xd0020000) -#define PPB_BASE _u(0xe0000000) -#define PPB_NONSEC_BASE _u(0xe0020000) -#define EPPB_BASE _u(0xe0080000) - -// #include "hardware/regs/qmi.h" // https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2350/hardware_regs/include/hardware/regs/qmi.h -// Thats a lot of content... -#define QMI_M0_TIMING_CLKDIV_LSB _u(0) -#define QMI_M0_TIMING_CLKDIV_BITS _u(0x000000ff) -#define QMI_M0_TIMING_RXDELAY_LSB _u(8) -#define QMI_M0_TIMING_RXDELAY_BITS _u(0x00000700) -#define QMI_M0_TIMING_COOLDOWN_RESET _u(0x1) -#define QMI_M0_TIMING_COOLDOWN_BITS _u(0xc0000000) -#define QMI_M0_TIMING_COOLDOWN_MSB _u(31) -#define QMI_M0_TIMING_COOLDOWN_LSB _u(30) -#define QMI_M0_TIMING_COOLDOWN_ACCESS "RW" -#define QMI_M0_RCMD_PREFIX_RESET _u(0x03) -#define QMI_M0_RCMD_PREFIX_BITS _u(0x000000ff) -#define QMI_M0_RCMD_PREFIX_MSB _u(7) -#define QMI_M0_RCMD_PREFIX_LSB _u(0) -#define QMI_M0_RCMD_PREFIX_ACCESS "RW" -#define QMI_M0_RFMT_PREFIX_WIDTH_RESET _u(0x0) -#define QMI_M0_RFMT_PREFIX_WIDTH_BITS _u(0x00000003) -#define QMI_M0_RFMT_PREFIX_WIDTH_MSB _u(1) -#define QMI_M0_RFMT_PREFIX_WIDTH_LSB _u(0) -#define QMI_M0_RFMT_PREFIX_WIDTH_ACCESS "RW" -#define QMI_M0_RFMT_PREFIX_WIDTH_VALUE_S _u(0x0) -#define QMI_M0_RFMT_PREFIX_WIDTH_VALUE_D _u(0x1) -#define QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q _u(0x2) - -#define QMI_M0_RFMT_ADDR_WIDTH_RESET _u(0x0) -#define QMI_M0_RFMT_ADDR_WIDTH_BITS _u(0x0000000c) -#define QMI_M0_RFMT_ADDR_WIDTH_MSB _u(3) -#define QMI_M0_RFMT_ADDR_WIDTH_LSB _u(2) -#define QMI_M0_RFMT_ADDR_WIDTH_ACCESS "RW" -#define QMI_M0_RFMT_ADDR_WIDTH_VALUE_S _u(0x0) -#define QMI_M0_RFMT_ADDR_WIDTH_VALUE_D _u(0x1) -#define QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q _u(0x2) - -#define QMI_M0_RFMT_SUFFIX_WIDTH_RESET _u(0x0) -#define QMI_M0_RFMT_SUFFIX_WIDTH_BITS _u(0x00000030) -#define QMI_M0_RFMT_SUFFIX_WIDTH_MSB _u(5) -#define QMI_M0_RFMT_SUFFIX_WIDTH_LSB _u(4) -#define QMI_M0_RFMT_SUFFIX_WIDTH_ACCESS "RW" -#define QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_S _u(0x0) -#define QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_D _u(0x1) -#define QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q _u(0x2) - -#define QMI_M0_RFMT_DUMMY_WIDTH_RESET _u(0x0) -#define QMI_M0_RFMT_DUMMY_WIDTH_BITS _u(0x000000c0) -#define QMI_M0_RFMT_DUMMY_WIDTH_MSB _u(7) -#define QMI_M0_RFMT_DUMMY_WIDTH_LSB _u(6) -#define QMI_M0_RFMT_DUMMY_WIDTH_ACCESS "RW" -#define QMI_M0_RFMT_DUMMY_WIDTH_VALUE_S _u(0x0) -#define QMI_M0_RFMT_DUMMY_WIDTH_VALUE_D _u(0x1) -#define QMI_M0_RFMT_DUMMY_WIDTH_VALUE_Q _u(0x2) - -#define QMI_M0_RFMT_DATA_WIDTH_RESET _u(0x0) -#define QMI_M0_RFMT_DATA_WIDTH_BITS _u(0x00000300) -#define QMI_M0_RFMT_DATA_WIDTH_MSB _u(9) -#define QMI_M0_RFMT_DATA_WIDTH_LSB _u(8) -#define QMI_M0_RFMT_DATA_WIDTH_ACCESS "RW" -#define QMI_M0_RFMT_DATA_WIDTH_VALUE_S _u(0x0) -#define QMI_M0_RFMT_DATA_WIDTH_VALUE_D _u(0x1) -#define QMI_M0_RFMT_DATA_WIDTH_VALUE_Q _u(0x2) - -#define QMI_M0_RFMT_PREFIX_LEN_RESET _u(0x1) -#define QMI_M0_RFMT_PREFIX_LEN_BITS _u(0x00001000) -#define QMI_M0_RFMT_PREFIX_LEN_MSB _u(12) -#define QMI_M0_RFMT_PREFIX_LEN_LSB _u(12) -#define QMI_M0_RFMT_PREFIX_LEN_ACCESS "RW" -#define QMI_M0_RFMT_PREFIX_LEN_VALUE_NONE _u(0x0) -#define QMI_M0_RFMT_PREFIX_LEN_VALUE_8 _u(0x1) - -#define QMI_M0_RCMD_OFFSET _u(0x00000014) -#define QMI_M0_RCMD_BITS _u(0x0000ffff) -#define QMI_M0_RCMD_RESET _u(0x0000a003) - -#define QMI_M0_TIMING_OFFSET _u(0x0000000c) -#define QMI_M0_TIMING_BITS _u(0xf3fff7ff) -#define QMI_M0_TIMING_RESET _u(0x40000004) - -#define QMI_M0_RFMT_OFFSET _u(0x00000010) -#define QMI_M0_RFMT_BITS _u(0x1007d3ff) -#define QMI_M0_RFMT_RESET _u(0x00001000) - -// ---------------------------------------------------------------------------- -// Config section -// ---------------------------------------------------------------------------- -// It should be possible to support most flash devices by modifying this section - -// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV. -// This must be a positive integer. -// The bootrom is very conservative with SPI frequency, but here we should be -// as aggressive as possible. - -#ifndef PICO_FLASH_SPI_CLKDIV -#define PICO_FLASH_SPI_CLKDIV 4 -#endif -#if (PICO_FLASH_SPI_CLKDIV << QMI_M0_TIMING_CLKDIV_LSB) & ~QMI_M0_TIMING_CLKDIV_BITS -#error "CLKDIV greater than maximum" -#endif - -// RX sampling delay is measured in units of one half clock cycle. - -#ifndef PICO_FLASH_SPI_RXDELAY -#define PICO_FLASH_SPI_RXDELAY 1 -#endif -#if (PICO_FLASH_SPI_RXDELAY << QMI_M0_TIMING_RXDELAY_LSB) & ~QMI_M0_TIMING_RXDELAY_BITS -#error "RX delay greater than maximum" -#endif - -#define CMD_READ 0x03 - -// ---------------------------------------------------------------------------- -// Register initialisation values -- same in Arm/RISC-V code. -// ---------------------------------------------------------------------------- - -// The QMI is automatically configured for 03h XIP straight out of reset, -// but this code can't assume it's still in that state. Set up memory -// window 0 for 03h serial reads. - -// Setup timing parameters: short sequential-access cooldown, configured -// CLKDIV and RXDELAY, and no constraints on CS max assertion, CS min -// deassertion, or page boundary burst breaks. - - -#define INIT_M0_TIMING ((1 << QMI_M0_TIMING_COOLDOWN_LSB) |(PICO_FLASH_SPI_RXDELAY << QMI_M0_TIMING_RXDELAY_LSB) |(PICO_FLASH_SPI_CLKDIV << QMI_M0_TIMING_CLKDIV_LSB) |0) - -// Set command constants -#define INIT_M0_RCMD (CMD_READ << QMI_M0_RCMD_PREFIX_LSB | 0) - -// Set read format to all-serial with a command prefix -#define INIT_M0_RFMT ((QMI_M0_RFMT_PREFIX_WIDTH_VALUE_S << QMI_M0_RFMT_PREFIX_WIDTH_LSB) | (QMI_M0_RFMT_ADDR_WIDTH_VALUE_S << QMI_M0_RFMT_ADDR_WIDTH_LSB) | (QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_S << QMI_M0_RFMT_SUFFIX_WIDTH_LSB) | (QMI_M0_RFMT_DUMMY_WIDTH_VALUE_S << QMI_M0_RFMT_DUMMY_WIDTH_LSB) | (QMI_M0_RFMT_DATA_WIDTH_VALUE_S << QMI_M0_RFMT_DATA_WIDTH_LSB) | (QMI_M0_RFMT_PREFIX_LEN_VALUE_8 << QMI_M0_RFMT_PREFIX_LEN_LSB) | 0) - - -// load_r0 loads the register's value at address regaddr into R0 by stepping on r1 with the regaddr. -.macro load_r0 regaddr - ldr r1, =\regaddr // Load immediate value of regaddr with = pseudoinstr. May translate into several instructions depending on size of integer. - ldr r0, [r1] // Load memory at addr described by a register. -.endm - - -// fload_r0 loads the register's value at address regaddr into R0 and leaves rest of registers in same state. -.macro fload_r0 regaddr - push {r1} // Pushes contents of r1 onto stack. Stack grows downward in Cortex arch. - load_r0 regaddr - pop {r1} // Pops stack onto register r1. Braces can contain a range of addresses. -.endm - -// store_off_r3 is a helper that stores value into a register at address given by r3+off. Uses r0. -.macro store_off_r3 value, off - ldr r0, =\value // Store literal value we want to store at address r3+off into r0. - str r0, [r3, #\off] // Store value r0 into register at r3+off. -.endm - -// wait_bitclr checks value at address specified by register rx against bitmask until the AND between them yields 0. Steps on r0. -.macro wait_bitclr rx, bitmask -1: - tst \rx, #\bitmask // Perform bitwise AND between register and operand (register or immediate value) updating condition flags. Z flag set if AND yields zero. - bne 1b // Conditionally branch if Z flag set. BNE: Branch if Not Equal -> Will branch if Z set, so if r0&bitmask == 0. -.endm - -#define USESIO SIO_BASE -#define SIO_GPIOOUTSET_OFFSET _u(0x18) -#define SIO_GPIOOUTCLR_OFFSET _u(0x20) -#define pinfnSIO _u(1<<5) -#define pinfnUART _u(1<<2) -.macro pin_init pin, pinfn - #define pinmask (1<<\pin) - #define SIO_GPIOOECLR_OFFSET _u(0x40) - #define SIO_GPIOOESET_OFFSET _u(0x38) - #define pdtctrl_replace_bits _u(0x40|) - #define PADSBNK_IOPIN_OFFSET _u(4+4*\pin) - #define IOCTLREG _u(IO_BANK0_BASE+8*\pin+4) - #define padinputenablemsk _u(0x40) - #define padoutuptdisablemsk _u(0x80) - // First load in padbank io reg and replace bits in it. - ldr r3, =PADS_BANK0_BASE - ldr r0, [r3, PADSBNK_IOPIN_OFFSET] - bic r0, r0, (padinputenablemsk|padoutuptdisablemsk) // r0 &^= mask - orr r0, r0, padinputenablemsk - str r0, [r3, PADSBNK_IOPIN_OFFSET] - // Set the pin function in IO_BANK0. - ldr r3, =IOCTLREG - ldr r0, =\pinfn - str r0, [r3] - // Clear pinstate. - ldr r3, =USESIO - ldr r0, =pinmask - str r0, [r3, SIO_GPIOOECLR_OFFSET] // GPIO Output enable - str r0, [r3, SIO_GPIOOUTCLR_OFFSET] // Set pin to low. - .if \pinfn == pinfnSIO - str r0, [r3, SIO_GPIOOESET_OFFSET] // Assume pin is output: enable output. - .endif -.endm - -.macro pinout_init pin - pin_init \pin, pinfnSIO -.endm - -.macro pin_set pin, value - #define pinmsk _u(1<<\pin) - ldr r1, =pinmsk - ldr r0, =USESIO - .if \value == 0 - str r1, [r0, SIO_GPIOOUTCLR_OFFSET] - .else - str r1, [r0, SIO_GPIOOUTSET_OFFSET] - .endif -.endm - -.macro uart_init txpin - #define RESET_UART0 _u(0x4000000) - ldr r3, =RESETS_BASE - ldr r0, [r3] // Load value @r3 into r0. - orr r0, r0, #RESET_UART0 // Set reset bit for UART0. - str r0, [r3] // Storing the reset bit resets UART. - bic r0, r0, #RESET_UART0 // Unset the reset bit - str r0, [r3] // Clear the UART0 reset bit. - wait_bitclr r3, RESET_UART0 // Wait until peripheral is fully reset. - - // baud supported between ~200..6452000 - #define baud 115200 - #define div (8*125000000/baud) - #define ibrd _u(div>>7) - #define fbrd _u(((div&0x7f)+1)/2) - #define UART_IBRD_OFFSET _u(0x24) - #define UART_FBRD_OFFSET _u(0x28) - #define UART_LCRH_OFFSET _u(0x2C) - ldr r3, =UART0_BASE - // Start setting baud. - store_off_r3 ibrd, UART_IBRD_OFFSET - store_off_r3 fbrd, UART_FBRD_OFFSET - ldr r0, [r3, UART_LCRH_OFFSET] // Needs dummy write with contents in LCR. - str r0, [r3, UART_LCRH_OFFSET] // write back what we read. - #define uartenable (0x1) - #define uarttxenable (0x100) - #define UARTSETTINGS _u(uartenable|uarttxenable) - #define UART_CR_OFFSET _u(0x30) - ldr r0, [r3, UART_CR_OFFSET] - ldr r1, =UARTSETTINGS - orr r0, r0, r1 // Cannot use UARTSETTINGS as literal here, exceeds size of 255. - str r0, [r3, UART_CR_OFFSET] - // Configure pin 0 as UART (is Tx pin). - pin_init \txpin, pinfnUART -.endm - -.macro uart_write value - #define UART_FR_OFFSET _u(0x18) - ldr r0, =\value // Mark as immediate value, needs to be constant at compile time. - ldr r1, =UART0_BASE - str r0, [r1, UART_FR_OFFSET] // Write value in r0 to tx fifo. -.endm - -// ---------------------------------------------------------------------------- -// Start of 2nd Stage Boot Code -// ---------------------------------------------------------------------------- - -pico_default_asm_setup - -// On RP2350 boot stage2 is always called as a regular function, and should return normally -regular_func _stage2_boot -.ifdef __riscv - mv t0, ra - li a3, XIP_QMI_BASE - li a0, INIT_M0_TIMING - sw a0, QMI_M0_TIMING_OFFSET(a3) - li a0, INIT_M0_RCMD - sw a0, QMI_M0_RCMD_OFFSET(a3) - li a0, INIT_M0_RFMT - sw a0, QMI_M0_RFMT_OFFSET(a3) - // Exit routine. - jr t0 -.else - // Save link register for exit. lr hold the return address when a function call is made (bl or blx). - // We save it because we entered this bootload from the boot ROM, thus lr will contain the flash address - // immediately after this second-stage bootloader code. If bootloader is called by user lr will contain return address - // to resume execution after the bootloader ends. - // The bootloader uses r0..r1 as scratch and r3 holds the current register-of-interest base address. No other GPRs are used. - push {lr} - #define LED _u(25) - #define txpin _u(0) - // pinout_init LED - // pin_set LED, 1 - ldr r3, =XIP_QMI_BASE - // Note: STORE_OFF_R3 steps on r0. - // Here we configure/initialize QMI. - store_off_r3 INIT_M0_TIMING, QMI_M0_TIMING_OFFSET - store_off_r3 INIT_M0_RCMD, QMI_M0_RCMD_OFFSET - store_off_r3 INIT_M0_RFMT, QMI_M0_RFMT_OFFSET - // We pop the link value we saved in push {lr} above and set the program counter to it. This effectively returns from the function - // and returns to the calling function, this is because loading into pc causes the execution to jump to that address. - pop {pc} - // Declares the local symbol literals as a global symbol, making it accessible to the linker and other object files. - // ltorg instructs assembler to emit the literal pool at this point in the code. - // Places all pending literals (constants that cannot be encoded directly into instructions) at this point. // - // This ensures any ldr pseudo-instructions that reference literals have the corresponding data placed here. - // For example, when using the Thumb1 instruction set (16bit encoding) the ldr instruction offset range is limited to 0 to 1020 bytes (increments of 4 bytes), - // this is because it encodes offset as an 8 bit integer. If using Thumb2 (32bit) offset has range 0..4095, with 1 byte increment. - // - // We need to specify where we place the literals since we also need to have tight control of our bootloader size, limited to 256 bytes including 4 byte checksum. - // At the time of writing this bootloader literals section is empty, all instructions are fully encoded above. - .global literals - literals: - .ltorg -.endif - diff --git a/targets/rp2350_embedded_block.s b/targets/rp2350_embedded_block.s new file mode 100644 index 0000000000..f6202ed859 --- /dev/null +++ b/targets/rp2350_embedded_block.s @@ -0,0 +1,10 @@ +// Minimum viable block image from datasheet section 5.9.5.1, "Minimum Arm IMAGE_DEF" +.section .after_isr_vector, "a" +.p2align 2 +embedded_block: +.word 0xffffded3 +.word 0x10210142 +.word 0x000001ff +.word 0x00000000 +.word 0xab123579 +embedded_block_end: