aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/machine/machine_rp2_2350.go
diff options
context:
space:
mode:
authorPatricio Whittingslow <[email protected]>2024-12-18 15:36:30 -0300
committerGitHub <[email protected]>2024-12-18 19:36:30 +0100
commit37f35f8c910b05e2040433448546f41b34535b32 (patch)
tree32bdf01b1c2b8d75e9a7f1a24e5c62be9d432ce0 /src/machine/machine_rp2_2350.go
parent0d13e61d0cbe7aa82678a6dec7dda0115db82397 (diff)
downloadtinygo-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.go217
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)
+}