Add RP2350 support (#4459)

machine/rp2350: add support

* add linker scripts for rp2350
* add bootloader
* begin melding rp2040 and rp2350 APIs
* add UART
* add rp2350 boot patching
* Fix RP2350 memory layout (#4626)
* Remove rp2040-style second stage bootloader.
* Add 'minimum viable' IMAGE_DEF embedded block
* Create a pico2 specific target
* Implement rp2350 init, clock, and uart support
* Merge rp2 reset code back together
* Separate chip-specific clock definitions
* Clear pad isolation bit on rp2350
* Init UART in rp2350 runtime
* Correct usb/serial initialization order
* Implement jump-to-bootloader
* test: add pico2 to smoketests

---------

Signed-off-by: deadprogram <ron@hybridgroup.com>
Co-authored-by: Matthew Mets <matt.mets@cibomahto.com>
Co-authored-by: Matt Mets <matt@blinkinlabs.com>
Co-authored-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
Patricio Whittingslow
2024-12-18 15:36:30 -03:00
committed by GitHub
parent 0d13e61d0c
commit 37f35f8c91
33 changed files with 1349 additions and 294 deletions
+159
View File
@@ -0,0 +1,159 @@
//go:build rp2040 || rp2350
package machine
import (
"device/rp"
"runtime/interrupt"
)
// UART on the RP2040.
type UART struct {
Buffer *RingBuffer
Bus *rp.UART0_Type
Interrupt interrupt.Interrupt
}
// Configure the UART.
func (uart *UART) Configure(config UARTConfig) error {
initUART(uart)
// Default baud rate to 115200.
if config.BaudRate == 0 {
config.BaudRate = 115200
}
// Use default pins if pins are not set.
if config.TX == 0 && config.RX == 0 {
// use default pins
config.TX = UART_TX_PIN
config.RX = UART_RX_PIN
}
uart.SetBaudRate(config.BaudRate)
// default to 8-1-N
uart.SetFormat(8, 1, ParityNone)
// Enable the UART, both TX and RX
settings := uint32(rp.UART0_UARTCR_UARTEN |
rp.UART0_UARTCR_RXE |
rp.UART0_UARTCR_TXE)
const bits = rp.UART0_UARTCR_UARTEN | rp.UART0_UARTCR_TXE
if config.RTS != 0 {
settings |= rp.UART0_UARTCR_RTSEN
}
if config.CTS != 0 {
settings |= rp.UART0_UARTCR_CTSEN
}
uart.Bus.UARTCR.SetBits(settings)
// set GPIO mux to UART for the pins
if config.TX != NoPin {
config.TX.Configure(PinConfig{Mode: PinUART})
}
if config.RX != NoPin {
config.RX.Configure(PinConfig{Mode: PinUART})
}
if config.RTS != 0 {
config.RTS.Configure(PinConfig{Mode: PinOutput})
}
if config.CTS != 0 {
config.CTS.Configure(PinConfig{Mode: PinInput})
}
// Enable RX IRQ.
uart.Interrupt.SetPriority(0x80)
uart.Interrupt.Enable()
// setup interrupt on receive
uart.Bus.UARTIMSC.Set(rp.UART0_UARTIMSC_RXIM)
return nil
}
// SetBaudRate sets the baudrate to be used for the UART.
func (uart *UART) SetBaudRate(br uint32) {
div := 8 * 125 * MHz / br
ibrd := div >> 7
var fbrd uint32
switch {
case ibrd == 0:
ibrd = 1
fbrd = 0
case ibrd >= 65535:
ibrd = 65535
fbrd = 0
default:
fbrd = ((div & 0x7f) + 1) / 2
}
// set PL011 baud divisor registers
uart.Bus.UARTIBRD.Set(ibrd)
uart.Bus.UARTFBRD.Set(fbrd)
// PL011 needs a (dummy) line control register write.
// See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_uart/uart.c#L93-L95
uart.Bus.UARTLCR_H.SetBits(0)
}
// WriteByte writes a byte of data to the UART.
func (uart *UART) writeByte(c byte) error {
// wait until buffer is not full
for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_TXFF) {
gosched()
}
// write data
uart.Bus.UARTDR.Set(uint32(c))
return nil
}
func (uart *UART) flush() {
for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_BUSY) {
gosched()
}
}
// SetFormat for number of data bits, stop bits, and parity for the UART.
func (uart *UART) SetFormat(databits, stopbits uint8, parity UARTParity) error {
var pen, pev uint8
if parity != ParityNone {
pen = rp.UART0_UARTLCR_H_PEN
}
if parity == ParityEven {
pev = rp.UART0_UARTLCR_H_EPS
}
uart.Bus.UARTLCR_H.SetBits(uint32((databits-5)<<rp.UART0_UARTLCR_H_WLEN_Pos |
(stopbits-1)<<rp.UART0_UARTLCR_H_STP2_Pos |
pen | pev))
return nil
}
func initUART(uart *UART) {
var resetVal uint32
switch {
case uart.Bus == rp.UART0:
resetVal = rp.RESETS_RESET_UART0
case uart.Bus == rp.UART1:
resetVal = rp.RESETS_RESET_UART1
}
// reset UART
rp.RESETS.RESET.SetBits(resetVal)
rp.RESETS.RESET.ClearBits(resetVal)
for !rp.RESETS.RESET_DONE.HasBits(resetVal) {
}
}
// handleInterrupt should be called from the appropriate interrupt handler for
// this UART instance.
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_RXFE) {
}
uart.Receive(byte((uart.Bus.UARTDR.Get() & 0xFF)))
}