diff options
author | Patricio Whittingslow <[email protected]> | 2024-12-18 15:36:30 -0300 |
---|---|---|
committer | GitHub <[email protected]> | 2024-12-18 19:36:30 +0100 |
commit | 37f35f8c910b05e2040433448546f41b34535b32 (patch) | |
tree | 32bdf01b1c2b8d75e9a7f1a24e5c62be9d432ce0 /src/machine/machine_rp2_2350.go | |
parent | 0d13e61d0cbe7aa82678a6dec7dda0115db82397 (diff) | |
download | tinygo-37f35f8c910b05e2040433448546f41b34535b32.tar.gz tinygo-37f35f8c910b05e2040433448546f41b34535b32.zip |
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 <[email protected]>
Co-authored-by: Matthew Mets <[email protected]>
Co-authored-by: Matt Mets <[email protected]>
Co-authored-by: deadprogram <[email protected]>
Diffstat (limited to 'src/machine/machine_rp2_2350.go')
-rw-r--r-- | src/machine/machine_rp2_2350.go | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/machine/machine_rp2_2350.go b/src/machine/machine_rp2_2350.go new file mode 100644 index 000000000..54fc62b47 --- /dev/null +++ b/src/machine/machine_rp2_2350.go @@ -0,0 +1,217 @@ +//go:build rp2350 + +package machine + +import ( + "device/rp" + "runtime/volatile" + "unsafe" +) + +const ( + _NUMBANK0_GPIOS = 48 + _NUMBANK0_IRQS = 6 + rp2350ExtraReg = 1 + _NUMIRQ = 51 + notimpl = "rp2350: not implemented" + RESETS_RESET_Msk = 0x1fffffff + initUnreset = rp.RESETS_RESET_ADC | + rp.RESETS_RESET_SPI0 | + rp.RESETS_RESET_SPI1 | + rp.RESETS_RESET_UART0 | + rp.RESETS_RESET_UART1 | + rp.RESETS_RESET_USBCTRL + initDontReset = rp.RESETS_RESET_USBCTRL | + rp.RESETS_RESET_SYSCFG | + rp.RESETS_RESET_PLL_USB | + rp.RESETS_RESET_PLL_SYS | + rp.RESETS_RESET_PADS_QSPI | + rp.RESETS_RESET_IO_QSPI | + rp.RESETS_RESET_JTAG + padEnableMask = rp.PADS_BANK0_GPIO0_IE_Msk | + rp.PADS_BANK0_GPIO0_OD_Msk | + rp.PADS_BANK0_GPIO0_ISO_Msk +) + +const ( + PinOutput PinMode = iota + PinInput + PinInputPulldown + PinInputPullup + PinAnalog + PinUART + PinPWM + PinI2C + PinSPI + PinPIO0 + PinPIO1 + PinPIO2 +) + +const ( + ClkGPOUT0 clockIndex = iota // GPIO Muxing 0 + ClkGPOUT1 // GPIO Muxing 1 + ClkGPOUT2 // GPIO Muxing 2 + ClkGPOUT3 // GPIO Muxing 3 + ClkRef // Watchdog and timers reference clock + ClkSys // Processors, bus fabric, memory, memory mapped registers + ClkPeri // Peripheral clock for UART and SPI + ClkHSTX // High speed interface + ClkUSB // USB clock + ClkADC // ADC clock + NumClocks +) + +func CalcClockDiv(srcFreq, freq uint32) uint32 { + // Div register is 4.16 int.frac divider so multiply by 2^16 (left shift by 16) + return uint32((uint64(srcFreq) << 16) / uint64(freq)) +} + +type clocksType struct { + clk [NumClocks]clockType + dftclk_xosc_ctrl volatile.Register32 + dftclk_rosc_ctrl volatile.Register32 + dftclk_lposc_ctrl volatile.Register32 + resus struct { + ctrl volatile.Register32 + status volatile.Register32 + } + fc0 fc + wakeEN0 volatile.Register32 + wakeEN1 volatile.Register32 + sleepEN0 volatile.Register32 + sleepEN1 volatile.Register32 + enabled0 volatile.Register32 + enabled1 volatile.Register32 + intR volatile.Register32 + intE volatile.Register32 + intF volatile.Register32 + intS volatile.Register32 +} + +// GPIO function selectors +const ( + // Connect the high-speed transmit peripheral (HSTX) to GPIO. + fnHSTX pinFunc = 0 + fnSPI pinFunc = 1 // Connect one of the internal PL022 SPI peripherals to GPIO + fnUART pinFunc = 2 + fnI2C pinFunc = 3 + // Connect a PWM slice to GPIO. There are eight PWM slices, + // each with two outputchannels (A/B). The B pin can also be used as an input, + // for frequency and duty cyclemeasurement + fnPWM pinFunc = 4 + // Software control of GPIO, from the single-cycle IO (SIO) block. + // The SIO function (F5)must be selected for the processors to drive a GPIO, + // but the input is always connected,so software can check the state of GPIOs at any time. + fnSIO pinFunc = 5 + // Connect one of the programmable IO blocks (PIO) to GPIO. PIO can implement a widevariety of interfaces, + // and has its own internal pin mapping hardware, allowing flexibleplacement of digital interfaces on bank 0 GPIOs. + // The PIO function (F6, F7, F8) must beselected for PIO to drive a GPIO, but the input is always connected, + // so the PIOs canalways see the state of all pins. + fnPIO0, fnPIO1, fnPIO2 pinFunc = 6, 7, 8 + // General purpose clock outputs. Can drive a number of internal clocks (including PLL + // outputs) onto GPIOs, with optional integer divide. + fnGPCK pinFunc = 9 + // QSPI memory interface peripheral, used for execute-in-place from external QSPI flash or PSRAM memory devices. + fnQMI pinFunc = 9 + // USB power control signals to/from the internal USB controller. + fnUSB pinFunc = 10 + fnUARTAlt pinFunc = 11 + fnNULL pinFunc = 0x1f +) + +// Configure configures the gpio pin as per mode. +func (p Pin) Configure(config PinConfig) { + if p == NoPin { + return + } + p.init() + mask := uint32(1) << p + switch config.Mode { + case PinOutput: + p.setFunc(fnSIO) + rp.SIO.GPIO_OE_SET.Set(mask) + case PinInput: + p.setFunc(fnSIO) + p.pulloff() + case PinInputPulldown: + p.setFunc(fnSIO) + p.pulldown() + case PinInputPullup: + p.setFunc(fnSIO) + p.pullup() + case PinAnalog: + p.setFunc(fnNULL) + p.pulloff() + case PinUART: + p.setFunc(fnUART) + case PinPWM: + p.setFunc(fnPWM) + case PinI2C: + // IO config according to 4.3.1.3 of rp2040 datasheet. + p.setFunc(fnI2C) + p.pullup() + p.setSchmitt(true) + p.setSlew(false) + case PinSPI: + p.setFunc(fnSPI) + case PinPIO0: + p.setFunc(fnPIO0) + case PinPIO1: + p.setFunc(fnPIO1) + case PinPIO2: + p.setFunc(fnPIO2) + } +} + +var ( + timer = (*timerType)(unsafe.Pointer(rp.TIMER0)) +) + +// Enable or disable a specific interrupt on the executing core. +// num is the interrupt number which must be in [0,_NUMIRQ). +func irqSet(num uint32, enabled bool) { + if num >= _NUMIRQ { + return + } + + register_index := num / 32 + var mask uint32 = 1 << (num % 32) + + if enabled { + // Clear pending before enable + //(if IRQ is actually asserted, it will immediately re-pend) + if register_index == 0 { + rp.PPB.NVIC_ICPR0.Set(mask) + rp.PPB.NVIC_ISER0.Set(mask) + } else { + rp.PPB.NVIC_ICPR1.Set(mask) + rp.PPB.NVIC_ISER1.Set(mask) + } + } else { + if register_index == 0 { + rp.PPB.NVIC_ICER0.Set(mask) + } else { + rp.PPB.NVIC_ICER1.Set(mask) + } + } +} + +func (clks *clocksType) initRTC() {} // No RTC on RP2350. + +func (clks *clocksType) initTicks() { + rp.TICKS.SetTIMER0_CTRL_ENABLE(0) + rp.TICKS.SetTIMER0_CYCLES(12) + rp.TICKS.SetTIMER0_CTRL_ENABLE(1) +} + +func EnterBootloader() { + enterBootloader() +} + +// startTick starts the watchdog tick. +// On RP2040, the watchdog contained a tick generator used to generate a 1μs tick for the watchdog. This was also +// distributed to the system timer. On RP2350, the watchdog instead takes a tick input from the system-level ticks block. See Section 8.5. +func (wd *watchdogImpl) startTick(cycles uint32) { + rp.TICKS.WATCHDOG_CTRL.SetBits(1) +} |