Add initial U-Boot architecture support for the RP2350 SoC. RP2350 specs: - CPU: Dual-core Arm Cortex-M33 or dual-core RISC-V Hazard3 @ 150MHz. - Memory: 520 KB on-chip SRAM, 4 MB on-board QSPI flash.
Only Arm core support is added here. The architecture is added under arch/arm/mach-rp2xxx/. This patch implements early SoC bring-up: - XOSC (12MHz crystal) startup - PLL_SYS configuration to 150MHz - CLK_REF/CLK_SYS/CLK_PERI clock switching - UART1 early console init (115200 8N1) Cortex-M33 is an Armv8-M core, but U-Boot does not yet have a CPU_V8M architecture variant. Currently there is no arch_cpu_init() setup for this architecture. Signed-off-by: Bhargav Das <[email protected]> --- arch/arm/Kconfig | 7 + arch/arm/Makefile | 2 + arch/arm/include/asm/arch-rp2xxx/rp2350.h | 352 ++++++++++++++++++++++ arch/arm/mach-rp2xxx/Kconfig | 58 ++++ arch/arm/mach-rp2xxx/Makefile | 4 + arch/arm/mach-rp2xxx/image_def.S | 23 ++ arch/arm/mach-rp2xxx/rp2350.c | 213 +++++++++++++ arch/arm/mach-rp2xxx/u-boot.lds | 94 ++++++ 8 files changed, 753 insertions(+) create mode 100644 arch/arm/include/asm/arch-rp2xxx/rp2350.h create mode 100644 arch/arm/mach-rp2xxx/Kconfig create mode 100644 arch/arm/mach-rp2xxx/Makefile create mode 100644 arch/arm/mach-rp2xxx/image_def.S create mode 100644 arch/arm/mach-rp2xxx/rp2350.c create mode 100644 arch/arm/mach-rp2xxx/u-boot.lds diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1b474a346bf..af582e91383 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2033,6 +2033,10 @@ config ARCH_STM32 select DM_SERIAL imply CMD_DM +config ARCH_RP2XXX + bool "Raspberry Pi RP2xxx SoCs" + select CPU_V7M + config ARCH_STI bool "Support STMicroelectronics SoCs" select CPU_V7A @@ -2293,6 +2297,9 @@ config SYS_KWD_CONFIG Path within the source directory to the kwbimage.cfg file to use when packaging the U-Boot image for use. + +source "arch/arm/mach-rp2xxx/Kconfig" + source "arch/arm/mach-airoha/Kconfig" source "arch/arm/mach-apple/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index de975fc9368..2131e92a6a4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -101,6 +101,8 @@ machine-$(CONFIG_ARCH_ZYNQMP_R5) += zynqmp-r5 machine-$(CONFIG_MACH_IMX) += imx +machine-$(CONFIG_ARCH_RP2XXX) += rp2xxx + machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) PLATFORM_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs)) diff --git a/arch/arm/include/asm/arch-rp2xxx/rp2350.h b/arch/arm/include/asm/arch-rp2xxx/rp2350.h new file mode 100644 index 00000000000..738fa20be96 --- /dev/null +++ b/arch/arm/include/asm/arch-rp2xxx/rp2350.h @@ -0,0 +1,352 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _MACH_RP2350_H_ +#define _MACH_RP2350_H_ + +/* + * RP2350 Memory Map from RP2350 Datasheet. Datasheet sections are + * mentioned against the respective ranges. + * + * 0x00000000 - 0x00007fff Boot ROM (32KB), sec 3.8.2.2 + * 0x10000000 - 0x11FFFFFF XIP QSPI interface range (up to 32MB), sec 2.2.2. + * 0x20000000 - 0x20081FFF SRAM (520KB), sec 4.2. + * 0x40000000 APB Peripherals base, sec 2.2.4. + * 0x50000000 AHB Peripherals base, sec 2.2.5. + * 0xD0000000 Core-local peripherals (SIO) base, sec 2.2.6. + * 0xE0000000 Cortex-M33 Private Peripheral Bus, sec 2.2.7. + */ + +/* Flash XIP base - U-Boot should start from here */ +#define RP2350_FLASH_XIP_BASE 0x10000000 +#define RP2350_FLASH_XIP_SIZE (32 * 1024 * 1024) /* 32MB, override in board files */ + +/* SRAM - 520KB across 10 banks */ +#define RP2350_SRAM_BASE 0x20000000 +#define RP2350_SRAM_SIZE (520 * 1024) /* 520KB */ + +#define RP2350_SRAM_TOP (RP2350_SRAM_BASE + RP2350_SRAM_SIZE) + +/* + * APB Peripheral Base Addresses + */ +#define RP2350_APB_BASE 0x40000000 +#define RP2350_SYSINFO_BASE 0x40000000 +#define RP2350_SYSCFG_BASE 0x40008000 +#define RP2350_CLOCKS_BASE 0x40010000 +#define RP2350_PSM_BASE 0x40018000 +#define RP2350_RESETS_BASE 0x40020000 +#define RP2350_IO_BANK0_BASE 0x40028000 +#define RP2350_IO_QSPI_BASE 0x40030000 +#define RP2350_PADS_BANK0_BASE 0x40038000 +#define RP2350_PADS_QSPI_BASE 0x40040000 +#define RP2350_XOSC_BASE 0x40048000 +#define RP2350_PLL_SYS_BASE 0x40050000 +#define RP2350_PLL_USB_BASE 0x40058000 +#define RP2350_ACCESSCTRL_BASE 0x40060000 +#define RP2350_BUSCTRL_BASE 0x40068000 +#define RP2350_UART0_BASE 0x40070000 +#define RP2350_UART1_BASE 0x40078000 +#define RP2350_SPI0_BASE 0x40080000 +#define RP2350_SPI1_BASE 0x40088000 +#define RP2350_I2C0_BASE 0x40090000 +#define RP2350_I2C1_BASE 0x40098000 +#define RP2350_ADC_BASE 0x400a0000 +#define RP2350_PWM_BASE 0x400a8000 +#define RP2350_TIMER0_BASE 0x400b0000 +#define RP2350_TIMER1_BASE 0x400b8000 +#define RP2350_HSTX_CTRL_BASE 0x400c0000 +#define RP2350_XIP_CTRL_BASE 0x400c8000 +#define RP2350_XIP_QMI_BASE 0x400d0000 +#define RP2350_WATCHDOG_BASE 0x400d8000 +#define RP2350_BOOTRAM_BASE 0x400e0000 +#define RP2350_ROSC_BASE 0x400e8000 +#define RP2350_TRNG_BASE 0x400f0000 +#define RP2350_SHA256_BASE 0x400f8000 +#define RP2350_POWMAN_BASE 0x40100000 +#define RP2350_TICKS_BASE 0x40108000 +#define RP2350_OTP_BASE 0x40120000 +#define RP2350_OTP_DATA_BASE 0x40130000 +#define RP2350_OTP_DATA_RAW_BASE 0x40134000 +#define RP2350_OTP_DATA_GUARDED_BASE 0x40138000 +#define RP2350_OTP_DATA_RAW_GUARDED_BASE 0x4013c000 +#define RP2350_CORESIGHT_PERIPH_BASE 0x40140000 +#define RP2350_CORESIGHT_ROMTABLE_BASE 0x40140000 +#define RP2350_CORESIGHT_AHB_AP_CORE0_BASE 0x40142000 +#define RP2350_CORESIGHT_AHB_AP_CORE1_BASE 0x40144000 +#define RP2350_CORESIGHT_TIMESTAMP_GEN_BASE 0x40146000 +#define RP2350_CORESIGHT_ATB_FUNNEL_BASE 0x40147000 +#define RP2350_CORESIGHT_TPIU_BASE 0x40148000 +#define RP2350_CORESIGHT_CTI_BASE 0x40149000 +#define RP2350_CORESIGHT_APB_AP_RISCV_BASE 0x4014a000 +#define RP2350_GLITCH_DETECTOR_BASE 0x40158000 +#define RP2350_TBMAN_BASE 0x40160000 + +/* + * AHB Peripheral Base Addresses + */ +#define RP2350_AHB_BASE 0x50000000 +#define RP2350_DMA_BASE 0x50000000 +#define RP2350_USBCTRL_BASE 0x50100000 +#define RP2350_USBCTRL_DPRAM_BASE 0x50100000 +#define RP2350_USBCTRL_REGS_BASE 0x50110000 +#define RP2350_PIO0_BASE 0x50200000 +#define RP2350_PIO1_BASE 0x50300000 +#define RP2350_PIO2_BASE 0x50400000 +#define RP2350_XIP_AUX_BASE 0x50500000 +#define RP2350_HSTX_FIFO_BASE 0x50600000 +#define RP2350_CORESIGHT_TRACE_BASE 0x50700000 + +/* SIO (Core-local peripherals) Base Address */ +#define RP2350_SIO_BASE 0xd0000000 +#define RP2350_SIO_NONSEC_BASE 0xd0020000 + +/* One universal macro to handle every single block and offset */ +#define RP2350_REG(base, offset) ((base) + (offset)) + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> + +/* + * RESETS peripheral register map + * Used to hold peripherals in reset and release them + */ +struct rp2350_resets_regs { + u32 reset; /* 0x00 - Reset control */ + u32 wdsel; /* 0x04 - Watchdog select */ + u32 reset_done; /* 0x08 - Reset done status */ +}; + +#define RP2350_RESETS ((struct rp2350_resets_regs *)RP2350_RESETS_BASE) + +/* Reset bits for peripherals we care about */ +#define RESETS_RESET_UART0 BIT(26) +#define RESETS_RESET_UART1 BIT(27) +#define RESETS_RESET_PLL_SYS BIT(14) +#define RESETS_RESET_PLL_USB BIT(15) + +/* + * XOSC (Crystal Oscillator) register map + * RP2350 uses a 12MHz crystal + */ +struct rp2350_xosc_regs { + u32 ctrl; /* 0x00 - Crystal oscillator control */ + u32 status; /* 0x04 - Crystal oscillator status */ + u32 dormant; /* 0x08 - Dormant control */ + u32 startup; /* 0x0C - Startup delay */ + u32 count; /* 0x10 - Counter */ +}; + +#define RP2350_XOSC ((struct rp2350_xosc_regs *)RP2350_XOSC_BASE) + +#define XOSC_CTRL_ENABLE 0xFAB000 /* Magic enable value, disable is 0xD1E */ +#define XOSC_CTRL_FREQ_RANGE_1_15MHZ 0xAA0 +#define XOSC_STATUS_STABLE BIT(31) +#define XOSC_STARTUP_DELAY 47 /* ~1ms at 12MHz, ref sec 8.2.4. */ + +/* + * PLL register map + * Both PLL_SYS and PLL_USB use same layout + */ +struct rp2350_pll_regs { + u32 cs; /* 0x00 - Control and status */ + u32 pwr; /* 0x04 - Power control */ + u32 fbdiv_int; /* 0x08 - Feedback divisor integer */ + u32 prim; /* 0x0C - Post divisors */ +}; + +#define RP2350_PLL_SYS ((struct rp2350_pll_regs *)RP2350_PLL_SYS_BASE) +#define RP2350_PLL_USB ((struct rp2350_pll_regs *)RP2350_PLL_USB_BASE) + +/* PLL CS register bits */ +#define PLL_CS_LOCK BIT(31) +#define PLL_CS_BYPASS BIT(8) +#define PLL_CS_REFDIV_SHIFT 0 +#define PLL_CS_REFDIV_MASK 0x3F + +/* PLL PWR register bits */ +#define PLL_PWR_PD BIT(0) /* Main power down */ +#define PLL_PWR_DSMPD BIT(2) /* DSM power down */ +#define PLL_PWR_POSTDIVPD BIT(3) /* Post divider power down */ +#define PLL_PWR_VCOPD BIT(5) /* VCO power down */ + +/* PLL PRIM register */ +#define PLL_PRIM_POSTDIV1_SHIFT 16 +#define PLL_PRIM_POSTDIV2_SHIFT 12 + +/* + * CLOCKS register map + * Complete layout for the RP2350 CLOCKS block as defined in the datasheet. + * Each clock source has CTRL/DIV/SELECTED registers; + * As mentioned in Datasheet section 8.1.7 List of registers + */ +struct rp2350_clocks_regs { + u32 clk_gpout0_ctrl; /* 0x00 */ + u32 clk_gpout0_div; /* 0x04 */ + u32 clk_gpout0_selected; /* 0x08 */ + u32 clk_gpout1_ctrl; /* 0x0C */ + u32 clk_gpout1_div; /* 0x10 */ + u32 clk_gpout1_selected; /* 0x14 */ + u32 clk_gpout2_ctrl; /* 0x18 */ + u32 clk_gpout2_div; /* 0x1C */ + u32 clk_gpout2_selected; /* 0x20 */ + u32 clk_gpout3_ctrl; /* 0x24 */ + u32 clk_gpout3_div; /* 0x28 */ + u32 clk_gpout3_selected; /* 0x2C */ + u32 clk_ref_ctrl; /* 0x30 */ + u32 clk_ref_div; /* 0x34 */ + u32 clk_ref_selected; /* 0x38 */ + u32 clk_sys_ctrl; /* 0x3C */ + u32 clk_sys_div; /* 0x40 */ + u32 clk_sys_selected; /* 0x44 */ + u32 clk_peri_ctrl; /* 0x48 */ + u32 clk_peri_div; /* 0x4C */ + u32 clk_peri_selected; /* 0x50 */ + u32 clk_hstx_ctrl; /* 0x54 */ + u32 clk_hstx_div; /* 0x58 */ + u32 clk_hstx_selected; /* 0x5C */ + u32 clk_usb_ctrl; /* 0x60 */ + u32 clk_usb_div; /* 0x64 */ + u32 clk_usb_selected; /* 0x68 */ + u32 clk_adc_ctrl; /* 0x6C */ + u32 clk_adc_div; /* 0x70 */ + u32 clk_adc_selected; /* 0x74 */ + u32 dftclk_xosc_ctrl; /* 0x78 */ + u32 dftclk_rosc_ctrl; /* 0x7C */ + u32 dftclk_lposc_ctrl; /* 0x80 */ + u32 clk_sys_resus_ctrl; /* 0x84 */ + u32 clk_sys_resus_status; /* 0x88 */ + u32 fc0_ref_khz; /* 0x8C */ + u32 fc0_min_khz; /* 0x90 */ + u32 fc0_max_khz; /* 0x94 */ + u32 fc0_delay; /* 0x98 */ + u32 fc0_interval; /* 0x9C */ + u32 fc0_src; /* 0xA0 */ + u32 fc0_status; /* 0xA4 */ + u32 fc0_result; /* 0xA8 */ + u32 wake_en0; /* 0xAC */ + u32 wake_en1; /* 0xB0 */ + u32 sleep_en0; /* 0xB4 */ + u32 sleep_en1; /* 0xB8 */ + u32 enabled0; /* 0xBC */ + u32 enabled1; /* 0xC0 */ + u32 intr; /* 0xC4 */ + u32 inte; /* 0xC8 */ + u32 intf; /* 0xCC */ + u32 ints; /* 0xD0 */ +}; + +#define RP2350_CLOCKS ((struct rp2350_clocks_regs *)RP2350_CLOCKS_BASE) + +/* Clock source selections */ +#define CLK_REF_SRC_XOSC 0x2 +#define CLK_SYS_SRC_PLL_SYS 0x0 +#define CLK_PERI_SRC_CLK_SYS 0x0 +#define CLK_SYS_SRC_AUX 0x1 + +/* + * UART register map (PL011 compatible) + * This is standard ARM PL011 - same as used in many ARM SoCs + */ +struct rp2350_uart_regs { + u32 dr; /* 0x00 - Data register */ + u32 rsr; /* 0x04 - Receive status / error clear */ + u32 reserved0[4]; + u32 fr; /* 0x18 - Flag register */ + u32 reserved1; + u32 ilpr; /* 0x20 - IrDA low-power counter */ + u32 ibrd; /* 0x24 - Integer baud rate divisor */ + u32 fbrd; /* 0x28 - Fractional baud rate divisor */ + u32 lcr_h; /* 0x2C - Line control */ + u32 cr; /* 0x30 - Control */ + u32 ifls; /* 0x34 - Interrupt FIFO level select */ + u32 imsc; /* 0x38 - Interrupt mask set/clear */ + u32 ris; /* 0x3C - Raw interrupt status */ + u32 mis; /* 0x40 - Masked interrupt status */ + u32 icr; /* 0x44 - Interrupt clear */ + u32 dmacr; /* 0x48 - DMA control */ +}; + +#define RP2350_UART0 ((struct rp2350_uart_regs *)RP2350_UART0_BASE) +#define RP2350_UART1 ((struct rp2350_uart_regs *)RP2350_UART1_BASE) + +/* UART Flag register bits */ +#define UART_FR_TXFF BIT(5) /* TX FIFO full */ +#define UART_FR_RXFE BIT(4) /* RX FIFO empty */ +#define UART_FR_BUSY BIT(3) /* UART busy */ +#define UART_FR_TXFE BIT(7) /* TX FIFO empty */ + +/* UART Line Control bits */ +#define UART_LCR_H_WLEN_8 (0x3 << 5) /* 8 bit word length */ +#define UART_LCR_H_FEN BIT(4) /* FIFO enable */ + +/* UART Control bits */ +#define UART_CR_UARTEN BIT(0) /* UART enable */ +#define UART_CR_TXE BIT(8) /* TX enable */ +#define UART_CR_RXE BIT(9) /* RX enable */ + +#define RP2350_IO_BANK0_GPIO_CTRL(n) RP2350_REG(RP2350_IO_BANK0_BASE, 0x04 + (n) * 0x08) +#define RP2350_PADS_BANK0_GPIO(n) RP2350_REG(RP2350_PADS_BANK0_BASE, 0x04 + (n) * 0x04) + +/* GPIO function selections */ +#define RP2350_GPIO_FUNC_UART 2 +#define RP2350_PAD_IE BIT(6) +#define RP2350_PAD_OD BIT(7) +#define RP2350_PAD_ISO BIT(8) +#define RESETS_RESET_IO_BANK0 BIT(6) +#define RESETS_RESET_PADS_BANK0 BIT(9) + +/* Peripheral pointer, selected at compile time */ +#if CONFIG_RP2350_EARLY_UART_PORT == 0 +# define RP2350_EARLY_UART RP2350_UART0 +# define RESETS_RESET_EARLY_UART RESETS_RESET_UART0 +#elif CONFIG_RP2350_EARLY_UART_PORT == 1 +# define RP2350_EARLY_UART RP2350_UART1 +# define RESETS_RESET_EARLY_UART RESETS_RESET_UART1 +#else +# error "CONFIG_RP2350_EARLY_UART_PORT must be 0 or 1" +#endif + +/* + * System clock frequency after PLL init + * RP2350 default: 12MHz XOSC -> PLL -> 150MHz system clock + * + * PLL config for 150MHz: + * Same as SDK + * REFDIV=1, FBDIV=125, POSTDIV1=5, POSTDIV2=2 + * VCO = 12MHz * 125 = 1500MHz + * SYS = 1500MHz / 5 / 2 = 150MHz + */ +#define RP2350_XOSC_HZ 12000000 +#define RP2350_SYS_CLK_HZ 150000000 +#define RP2350_PERI_CLK_HZ RP2350_SYS_CLK_HZ + +/* UART baud rate calculation + * BAUDDIV = CLK / (16 * BAUD) + * After PLL init CLK_PERI sources from clk_sys which is PLL (150MHz): + * BAUDDIV = 150000000 / (16 * 115200) = 81.3802 + * IBRD = 81, FBRD = round(0.3802 * 64) = 24 + */ +#define RP2350_UART_IBRD_115200 81 +#define RP2350_UART_FBRD_115200 24 + +/* + * Atomic register access + * RP2350 (like RP2040) provides atomic set/clear/xor aliases + * for all peripheral registers via address offsets + */ +#define RP2350_ATOMIC_XOR_OFFSET 0x1000 +#define RP2350_ATOMIC_SET_OFFSET 0x2000 +#define RP2350_ATOMIC_CLR_OFFSET 0x3000 + +#define rp2350_reg_set(addr, val) \ + writel(val, (void *)((unsigned long)(addr) + RP2350_ATOMIC_SET_OFFSET)) +#define rp2350_reg_clr(addr, val) \ + writel(val, (void *)((unsigned long)(addr) + RP2350_ATOMIC_CLR_OFFSET)) + +void rp2350_soc_init(void); +void rp2350_uart_early_init(void); + +#endif /* ! __ASSEMBLY__ */ + +#endif /* _MACH_RP2350_H_ */ diff --git a/arch/arm/mach-rp2xxx/Kconfig b/arch/arm/mach-rp2xxx/Kconfig new file mode 100644 index 00000000000..c914cf7a521 --- /dev/null +++ b/arch/arm/mach-rp2xxx/Kconfig @@ -0,0 +1,58 @@ +if ARCH_RP2XXX + +config RP2350 + bool "RP2350 SoC" + help + Raspberry Pi RP2350 SoC. + Dual-core ARM Cortex-M33 with TrustZone, + 520KB SRAM, supports up to 16MB XIP QSPI flash. + +if RP2350 + +config RP2350_EARLY_UART + bool "Enable early UART init for RP2350" + default y + help + Initialises a UART very early in boot (before driver model) for + low-level debug output. The peripheral clocks, pad control, and + GPIO mux are configured here from fixed compile-time settings. + +if RP2350_EARLY_UART + +config RP2350_EARLY_UART_PORT + int "Early UART port number (0 or 1)" + range 0 1 + default 1 + help + Select which UART peripheral to use for early debug output. + 0 = UART0 (default; TX=GPIO0, RX=GPIO1) + 1 = UART1 (TX=GPIO4, RX=GPIO5) + +config RP2350_EARLY_UART_TX_GPIO + int "Early UART TX GPIO number" + default 0 if RP2350_EARLY_UART_PORT = 0 + default 4 if RP2350_EARLY_UART_PORT = 1 + help + GPIO pin for UART TX. Must match the UART port chosen above and + must be a pin that the RP2350 can route that UART function to. + Overrideable for non-standard board layouts. + +config RP2350_EARLY_UART_RX_GPIO + int "Early UART RX GPIO number" + default 1 if RP2350_EARLY_UART_PORT = 0 + default 5 if RP2350_EARLY_UART_PORT = 1 + help + GPIO pin for UART RX. Must match the UART port chosen above. + +endif # RP2350_EARLY_UART + +config TARGET_RPI_PICO2 + bool "Raspberry Pi Pico 2" + help + Raspberry Pi Pico 2 board based on RP2350 SoC. + +source "board/raspberrypi/pico2/Kconfig" + +endif # RP2350 + +endif # ARCH_RP2XXX diff --git a/arch/arm/mach-rp2xxx/Makefile b/arch/arm/mach-rp2xxx/Makefile new file mode 100644 index 00000000000..7da1928d6bb --- /dev/null +++ b/arch/arm/mach-rp2xxx/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += rp2350.o +obj-y += image_def.o diff --git a/arch/arm/mach-rp2xxx/image_def.S b/arch/arm/mach-rp2xxx/image_def.S new file mode 100644 index 00000000000..7854d94f6ea --- /dev/null +++ b/arch/arm/mach-rp2xxx/image_def.S @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* RP2350 PICOBIN metadata block - placed after the stored vector table */ + + .section .image_def, "a" + .align 4 + .global rp2350_image_def + +rp2350_image_def: + .word 0xffffded3 /* PICOBIN_BLOCK_MARKER_START */ + + /* IMAGE_TYPE: EXE | Secure | Arm | RP2350. */ + .byte 0x42 + .byte 0x01 + .hword 0x1021 + +rp2350_image_def_end_items: + .byte 0xff /* PICOBIN_BLOCK_ITEM_2BS_LAST */ + .hword (rp2350_image_def_end - rp2350_image_def - 16) / 4 + .byte 0x00 + + .word 0x00000000 /* Relative pointer to next block: self-loop */ + .word 0xab123579 /* PICOBIN_BLOCK_MARKER_END */ +rp2350_image_def_end: diff --git a/arch/arm/mach-rp2xxx/rp2350.c b/arch/arm/mach-rp2xxx/rp2350.c new file mode 100644 index 00000000000..69ef2daa89b --- /dev/null +++ b/arch/arm/mach-rp2xxx/rp2350.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <init.h> +#include <hang.h> +#include <asm/io.h> +#include <asm/armv7_mpu.h> +#include <asm/arch/rp2350.h> + +#define RP2350_RESET_WAIT_LOOPS 1000000U + +static void rp2350_wait_reset_done(u32 mask) +{ + unsigned int loops = RP2350_RESET_WAIT_LOOPS; + + while (loops--) { + if ((readl(&RP2350_RESETS->reset_done) & mask) == mask) + return; + } + /* something is very wrong */ + hang(); +} + +int print_cpuinfo(void) +{ + printf("CPU: Raspberry Pi RP2350\n"); + return 0; +} + +/* + * rp2350_xosc_init() - Start the 12MHz crystal oscillator + * + * The XOSC must be stable before we can configure the PLLs. + * RP2350 uses a 12MHz crystal on XIN/XOUT pins. + */ +static void rp2350_xosc_init(void) +{ + struct rp2350_xosc_regs *xosc = RP2350_XOSC; + + /* Set frequency range (1-15MHz) and startup delay (~1ms) */ + writel(XOSC_CTRL_FREQ_RANGE_1_15MHZ, &xosc->ctrl); + writel(XOSC_STARTUP_DELAY, &xosc->startup); + + /* Enable the oscillator */ + writel(XOSC_CTRL_FREQ_RANGE_1_15MHZ | XOSC_CTRL_ENABLE, &xosc->ctrl); + + /* Wait for XOSC to become stable */ + while (!(readl(&xosc->status) & XOSC_STATUS_STABLE)) + ; +} + +/* + * rp2350_pll_init() - Configure PLL_SYS for 150MHz + * + * Target: 150MHz system clock + * XOSC = 12MHz + * VCO = 12MHz * 125 = 1500MHz (FBDIV=125, REFDIV=1) + * SYS = 1500MHz / 5 / 2 = 150MHz (POSTDIV1=5, POSTDIV2=2) + */ +static void rp2350_pll_sys_init(void) +{ + struct rp2350_pll_regs *pll = RP2350_PLL_SYS; + struct rp2350_resets_regs *resets = RP2350_RESETS; + + /* Reset PLL */ + rp2350_reg_set(&resets->reset, RESETS_RESET_PLL_SYS); + rp2350_reg_clr(&resets->reset, RESETS_RESET_PLL_SYS); + rp2350_wait_reset_done(RESETS_RESET_PLL_SYS); + + /* Configure: REFDIV=1 */ + writel(1, &pll->cs); + + /* Power up only VCO and set feedback divisor */ + writel(PLL_PWR_POSTDIVPD | PLL_PWR_DSMPD, &pll->pwr); + + writel(125, &pll->fbdiv_int); /* VCO = 12 * 125 = 1500MHz */ + + /* Wait for VCO lock */ + while (!(readl(&pll->cs) & PLL_CS_LOCK)) + ; + + /* Set post dividers: POSTDIV1=5, POSTDIV2=2 -> 150MHz */ + writel((5 << PLL_PRIM_POSTDIV1_SHIFT) | (2 << PLL_PRIM_POSTDIV2_SHIFT), + &pll->prim); + + /* Power up post dividers except DSM */ + writel(PLL_PWR_DSMPD, &pll->pwr); +} + +/* + * rp2350_clocks_init() - Switch system clock to PLL_SYS (150MHz) + * + * After PLL is locked: + * 1. Switch CLK_REF to XOSC + * 2. Switch CLK_SYS to PLL_SYS + * 3. Enable CLK_PERI from CLK_SYS (for UART etc) + */ +static void rp2350_clocks_init(void) +{ + struct rp2350_clocks_regs *clocks = RP2350_CLOCKS; + + /* + * CLK_REF → XOSC + * SRC field [1:0] selects the glitchless mux input directly. + */ + clrsetbits_le32(&clocks->clk_ref_ctrl, 0x3, CLK_REF_SRC_XOSC); + while (!(readl(&clocks->clk_ref_selected) & BIT(CLK_REF_SRC_XOSC))) + ; + + /* + * CLK_SYS → PLL_SYS + */ + /* set AUXSRC = PLL_SYS, leave SRC unchanged */ + clrsetbits_le32(&clocks->clk_sys_ctrl, (0x7 << 5), + (CLK_SYS_SRC_PLL_SYS << 5)); + + /* switch glitchless mux to aux */ + clrsetbits_le32(&clocks->clk_sys_ctrl, 0x3, 0x1); + clrsetbits_le32(&clocks->clk_sys_ctrl, 0x3, CLK_SYS_SRC_AUX); + + /* Wait for CLK_SYS to settle on the aux source (bit 1) */ + while (!(readl(&clocks->clk_sys_selected) & BIT(1))) + ; + + /* + * CLK_PERI → CLK_SYS (150MHz) + * bit 11 = ENABLE + * bits [7:5] = AUXSRC: clk_sys + */ + writel(BIT(11) | (CLK_PERI_SRC_CLK_SYS << 5), &clocks->clk_peri_ctrl); +} + +/* + * rp2350_uart_early_init() - Minimal UART init for early console + * + * Called before driver model is up. Sets up UART1 at 115200 8N1. + * GPIO pins for UART1: TX=GPIO4, RX=GPIO5 + * Clock source: CLK_SYS == CLK_PERI == 150MHz + */ +void rp2350_uart_early_init(void) +{ + struct rp2350_uart_regs *uart = RP2350_EARLY_UART; + struct rp2350_resets_regs *resets = RP2350_RESETS; + u32 pad; + unsigned int tx = CONFIG_RP2350_EARLY_UART_TX_GPIO; + unsigned int rx = CONFIG_RP2350_EARLY_UART_RX_GPIO; + + /* Ensure IO_BANK0/PADS_BANK0 and UART1 are all out of reset. */ + rp2350_reg_clr(&resets->reset, + RESETS_RESET_IO_BANK0 | + RESETS_RESET_PADS_BANK0); + + rp2350_wait_reset_done(RESETS_RESET_IO_BANK0 | + RESETS_RESET_PADS_BANK0); + + /* + * Match SDK gpio_set_function() behavior for UART pins. + */ + pad = readl((void *)RP2350_PADS_BANK0_GPIO(tx)); + pad &= ~(RP2350_PAD_OD | RP2350_PAD_ISO); + pad |= RP2350_PAD_IE; + writel(pad, (void *)RP2350_PADS_BANK0_GPIO(tx)); + + pad = readl((void *)RP2350_PADS_BANK0_GPIO(rx)); + pad &= ~(RP2350_PAD_OD | RP2350_PAD_ISO); + pad |= RP2350_PAD_IE; + writel(pad, (void *)RP2350_PADS_BANK0_GPIO(rx)); + + writel(RP2350_GPIO_FUNC_UART, (void *)RP2350_IO_BANK0_GPIO_CTRL(tx)); + writel(RP2350_GPIO_FUNC_UART, (void *)RP2350_IO_BANK0_GPIO_CTRL(rx)); + + /* Release UART from reset */ + rp2350_reg_set(&resets->reset, RESETS_RESET_EARLY_UART); + rp2350_reg_clr(&resets->reset, RESETS_RESET_EARLY_UART); + rp2350_wait_reset_done(RESETS_RESET_EARLY_UART); + + /* Disable UART before configuration */ + writel(0, &uart->cr); + + /* Set baud rate: 115200 at 150MHz CLK_SYS/CLK_PERI + * BAUDDIV = 150000000 / (16 * 115200) = 81.3802 + * IBRD = 81, FBRD = round(0.3802 * 64) = 24 + */ + writel(RP2350_UART_IBRD_115200, &uart->ibrd); + writel(RP2350_UART_FBRD_115200, &uart->fbrd); + + /* 8N1, FIFO enabled */ + writel(UART_LCR_H_WLEN_8 | UART_LCR_H_FEN, &uart->lcr_h); + + /* Enable UART, TX, RX */ + writel(UART_CR_UARTEN | UART_CR_TXE | UART_CR_RXE, &uart->cr); +} + +/* + * rp2350_soc_init() - Full SoC initialization sequence + * + * Called from board_init_f() early path. + * Order matters: + * 1. XOSC - stable reference clock + * 2. PLL - multiply up to 150MHz + * 3. Clocks - switch system to PLL + * 4. UART - console ready + */ +void rp2350_soc_init(void) +{ + /* Start XOSC (12MHz crystal) for a stable, precise clock */ + rp2350_xosc_init(); + /* Setup PLL */ + rp2350_pll_sys_init(); + /* Setup clocks to use PLL and set 150MHz for clk_sys/clk_peri */ + rp2350_clocks_init(); + /* Now init UART - it will source clk_peri from clk_sys */ + rp2350_uart_early_init(); +} diff --git a/arch/arm/mach-rp2xxx/u-boot.lds b/arch/arm/mach-rp2xxx/u-boot.lds new file mode 100644 index 00000000000..200c37d6a13 --- /dev/null +++ b/arch/arm/mach-rp2xxx/u-boot.lds @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * RP2350 U-Boot linker script + * + * Based on arch/arm/cpu/u-boot.lds + * Modified to include RP2350 IMAGE_DEF block after vector table + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + __image_copy_start = ADDR(.text); + .text : + { + *(.vectors) /* Cortex-M33 vector table at image start */ + KEEP(*(.image_def)) /* RP2350 IMAGE_DEF block loop */ + arch/arm/cpu/armv7m/start.o (.text*) + } + + .efi_runtime : { + __efi_runtime_start = .; + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + __efi_runtime_stop = .; + } + + .text_rest : + { + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data*) + } + + . = ALIGN(4); + . = .; + . = ALIGN(4); + + __u_boot_list : { + KEEP(*(SORT(__u_boot_list*))); + } + + .efi_runtime_rel : { + __efi_runtime_rel_start = .; + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) + __efi_runtime_rel_stop = .; + } + + . = ALIGN(8); + __image_copy_end = .; + + .rel.dyn ALIGN(8) : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + . = ALIGN(8); + } + + _end = .; + _image_binary_end = .; + + .bss ADDR(.rel.dyn) (OVERLAY): { + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } + + /DISCARD/ : { *(.dynsym) } + /DISCARD/ : { *(.dynbss) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu.hash) } + /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.ARM.exidx*) } + /DISCARD/ : { *(.gnu.linkonce.armexidx.*) } +} + +ASSERT(_image_binary_end % 8 == 0, \ + "_image_binary_end must be 8-byte aligned for device tree"); -- 2.43.0
