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  }