github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_rp2040_rom.go (about) 1 //go:build tinygo && rp2040 2 3 package machine 4 5 import ( 6 "runtime/interrupt" 7 "unsafe" 8 ) 9 10 /* 11 // https://github.com/raspberrypi/pico-sdk 12 // src/rp2_common/pico_bootrom/include/pico/bootrom.h 13 14 #define ROM_FUNC_POPCOUNT32 ROM_TABLE_CODE('P', '3') 15 #define ROM_FUNC_REVERSE32 ROM_TABLE_CODE('R', '3') 16 #define ROM_FUNC_CLZ32 ROM_TABLE_CODE('L', '3') 17 #define ROM_FUNC_CTZ32 ROM_TABLE_CODE('T', '3') 18 #define ROM_FUNC_MEMSET ROM_TABLE_CODE('M', 'S') 19 #define ROM_FUNC_MEMSET4 ROM_TABLE_CODE('S', '4') 20 #define ROM_FUNC_MEMCPY ROM_TABLE_CODE('M', 'C') 21 #define ROM_FUNC_MEMCPY44 ROM_TABLE_CODE('C', '4') 22 #define ROM_FUNC_RESET_USB_BOOT ROM_TABLE_CODE('U', 'B') 23 #define ROM_FUNC_CONNECT_INTERNAL_FLASH ROM_TABLE_CODE('I', 'F') 24 #define ROM_FUNC_FLASH_EXIT_XIP ROM_TABLE_CODE('E', 'X') 25 #define ROM_FUNC_FLASH_RANGE_ERASE ROM_TABLE_CODE('R', 'E') 26 #define ROM_FUNC_FLASH_RANGE_PROGRAM ROM_TABLE_CODE('R', 'P') 27 #define ROM_FUNC_FLASH_FLUSH_CACHE ROM_TABLE_CODE('F', 'C') 28 #define ROM_FUNC_FLASH_ENTER_CMD_XIP ROM_TABLE_CODE('C', 'X') 29 30 #define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8)) 31 32 typedef unsigned char uint8_t; 33 typedef unsigned short uint16_t; 34 typedef unsigned long uint32_t; 35 typedef unsigned long size_t; 36 typedef unsigned long uintptr_t; 37 38 #define false 0 39 #define true 1 40 typedef int bool; 41 42 #define ram_func __attribute__((section(".ramfuncs"),noinline)) 43 44 typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code); 45 typedef void __attribute__((noreturn)) (*rom_reset_usb_boot_fn)(uint32_t, uint32_t); 46 typedef void (*flash_init_boot2_copyout_fn)(void); 47 typedef void (*flash_enable_xip_via_boot2_fn)(void); 48 typedef void (*flash_exit_xip_fn)(void); 49 typedef void (*flash_flush_cache_fn)(void); 50 typedef void (*flash_connect_internal_fn)(void); 51 typedef void (*flash_range_erase_fn)(uint32_t, size_t, uint32_t, uint16_t); 52 typedef void (*flash_range_program_fn)(uint32_t, const uint8_t*, size_t); 53 54 static inline __attribute__((always_inline)) void __compiler_memory_barrier(void) { 55 __asm__ volatile ("" : : : "memory"); 56 } 57 58 #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)(uintptr_t)(rom_address)) 59 60 void *rom_func_lookup(uint32_t code) { 61 rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18); 62 uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14); 63 return rom_table_lookup(func_table, code); 64 } 65 66 void reset_usb_boot(uint32_t usb_activity_gpio_pin_mask, uint32_t disable_interface_mask) { 67 rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT); 68 func(usb_activity_gpio_pin_mask, disable_interface_mask); 69 } 70 71 #define FLASH_BLOCK_ERASE_CMD 0xd8 72 73 #define FLASH_PAGE_SIZE (1u << 8) 74 #define FLASH_SECTOR_SIZE (1u << 12) 75 #define FLASH_BLOCK_SIZE (1u << 16) 76 77 #define BOOT2_SIZE_WORDS 64 78 #define XIP_BASE 0x10000000 79 80 static uint32_t boot2_copyout[BOOT2_SIZE_WORDS]; 81 static bool boot2_copyout_valid = false; 82 83 static ram_func void flash_init_boot2_copyout() { 84 if (boot2_copyout_valid) 85 return; 86 for (int i = 0; i < BOOT2_SIZE_WORDS; ++i) 87 boot2_copyout[i] = ((uint32_t *)XIP_BASE)[i]; 88 __compiler_memory_barrier(); 89 boot2_copyout_valid = true; 90 } 91 92 static ram_func void flash_enable_xip_via_boot2() { 93 ((void (*)(void))boot2_copyout+1)(); 94 } 95 96 #define IO_QSPI_BASE 0x40018000 97 #define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS 0x00000300 98 #define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_MSB 9 99 #define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB 8 100 #define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW 0x2 101 #define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH 0x3 102 103 #define XIP_SSI_BASE 0x18000000 104 #define ssi_hw ((ssi_hw_t *)XIP_SSI_BASE) 105 #define SSI_SR_OFFSET 0x00000028 106 #define SSI_DR0_OFFSET 0x00000060 107 #define SSI_SR_TFNF_BITS 0x00000002 108 #define SSI_SR_RFNE_BITS 0x00000008 109 110 void ram_func flash_cs_force(bool high) { 111 uint32_t field_val = high ? 112 IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : 113 IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW; 114 115 // &ioqspi_hw->io[1].ctrl 116 uint32_t *addr = (uint32_t*)(IO_QSPI_BASE + (1 * 8) + 4); 117 118 *addr = ((*addr) & !IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS) 119 | (field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB); 120 121 } 122 123 // See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c#L86 124 void ram_func flash_range_write(uint32_t offset, const uint8_t *data, size_t count) 125 { 126 flash_range_program_fn flash_range_program_func = (flash_range_program_fn) rom_func_lookup(ROM_FUNC_FLASH_RANGE_PROGRAM); 127 flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH); 128 flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP); 129 flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE); 130 131 flash_init_boot2_copyout(); 132 133 __compiler_memory_barrier(); 134 135 flash_connect_internal_func(); 136 flash_exit_xip_func(); 137 138 flash_range_program_func(offset, data, count); 139 flash_flush_cache_func(); 140 flash_enable_xip_via_boot2(); 141 } 142 143 void ram_func flash_erase_blocks(uint32_t offset, size_t count) 144 { 145 flash_range_erase_fn flash_range_erase_func = (flash_range_erase_fn) rom_func_lookup(ROM_FUNC_FLASH_RANGE_ERASE); 146 flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH); 147 flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP); 148 flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE); 149 150 flash_init_boot2_copyout(); 151 152 __compiler_memory_barrier(); 153 154 flash_connect_internal_func(); 155 flash_exit_xip_func(); 156 157 flash_range_erase_func(offset, count, FLASH_BLOCK_SIZE, FLASH_BLOCK_ERASE_CMD); 158 flash_flush_cache_func(); 159 flash_enable_xip_via_boot2(); 160 } 161 162 void ram_func flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) { 163 flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH); 164 flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP); 165 flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE); 166 167 flash_init_boot2_copyout(); 168 169 __compiler_memory_barrier(); 170 171 flash_connect_internal_func(); 172 flash_exit_xip_func(); 173 174 flash_cs_force(0); 175 size_t tx_remaining = count; 176 size_t rx_remaining = count; 177 // We may be interrupted -- don't want FIFO to overflow if we're distracted. 178 const size_t max_in_flight = 16 - 2; 179 while (tx_remaining || rx_remaining) { 180 uint32_t flags = *(uint32_t*)(XIP_SSI_BASE + SSI_SR_OFFSET); 181 bool can_put = !!(flags & SSI_SR_TFNF_BITS); 182 bool can_get = !!(flags & SSI_SR_RFNE_BITS); 183 if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) { 184 *(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET) = *txbuf++; 185 --tx_remaining; 186 } 187 if (can_get && rx_remaining) { 188 *rxbuf++ = (uint8_t)*(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET); 189 --rx_remaining; 190 } 191 } 192 flash_cs_force(1); 193 194 flash_flush_cache_func(); 195 flash_enable_xip_via_boot2(); 196 } 197 198 */ 199 import "C" 200 201 func enterBootloader() { 202 C.reset_usb_boot(0, 0) 203 } 204 205 func doFlashCommand(tx []byte, rx []byte) error { 206 if len(tx) != len(rx) { 207 return errFlashInvalidWriteLength 208 } 209 210 C.flash_do_cmd( 211 (*C.uint8_t)(unsafe.Pointer(&tx[0])), 212 (*C.uint8_t)(unsafe.Pointer(&rx[0])), 213 C.ulong(len(tx))) 214 215 return nil 216 } 217 218 // Flash related code 219 const memoryStart = C.XIP_BASE // memory start for purpose of erase 220 221 func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) { 222 if writeAddress(off)+uintptr(C.XIP_BASE) > FlashDataEnd() { 223 return 0, errFlashCannotWritePastEOF 224 } 225 226 state := interrupt.Disable() 227 defer interrupt.Restore(state) 228 229 // rp2040 writes to offset, not actual address 230 // e.g. real address 0x10003000 is written to at 231 // 0x00003000 232 address := writeAddress(off) 233 padded := f.pad(p) 234 235 C.flash_range_write(C.uint32_t(address), 236 (*C.uint8_t)(unsafe.Pointer(&padded[0])), 237 C.ulong(len(padded))) 238 239 return len(padded), nil 240 } 241 242 func (f flashBlockDevice) eraseBlocks(start, length int64) error { 243 address := writeAddress(start * f.EraseBlockSize()) 244 if address+uintptr(C.XIP_BASE) > FlashDataEnd() { 245 return errFlashCannotErasePastEOF 246 } 247 248 state := interrupt.Disable() 249 defer interrupt.Restore(state) 250 251 C.flash_erase_blocks(C.uint32_t(address), C.ulong(length*f.EraseBlockSize())) 252 253 return nil 254 }