1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _PICO_BOOTROM_H
8 #define _PICO_BOOTROM_H
9 
10 #include "pico.h"
11 
12 /** \file bootrom.h
13  * \defgroup pico_bootrom pico_bootrom
14  * Access to functions and data in the RP2040 bootrom
15  *
16  * This header may be included by assembly code
17  */
18 
19 // ROM FUNCTIONS
20 
21 #define ROM_FUNC_POPCOUNT32             ROM_TABLE_CODE('P', '3')
22 #define ROM_FUNC_REVERSE32              ROM_TABLE_CODE('R', '3')
23 #define ROM_FUNC_CLZ32                  ROM_TABLE_CODE('L', '3')
24 #define ROM_FUNC_CTZ32                  ROM_TABLE_CODE('T', '3')
25 #define ROM_FUNC_MEMSET                 ROM_TABLE_CODE('M', 'S')
26 #define ROM_FUNC_MEMSET4                ROM_TABLE_CODE('S', '4')
27 #define ROM_FUNC_MEMCPY                 ROM_TABLE_CODE('M', 'C')
28 #define ROM_FUNC_MEMCPY44               ROM_TABLE_CODE('C', '4')
29 #define ROM_FUNC_RESET_USB_BOOT         ROM_TABLE_CODE('U', 'B')
30 #define ROM_FUNC_CONNECT_INTERNAL_FLASH ROM_TABLE_CODE('I', 'F')
31 #define ROM_FUNC_FLASH_EXIT_XIP         ROM_TABLE_CODE('E', 'X')
32 #define ROM_FUNC_FLASH_RANGE_ERASE      ROM_TABLE_CODE('R', 'E')
33 #define ROM_FUNC_FLASH_RANGE_PROGRAM    ROM_TABLE_CODE('R', 'P')
34 #define ROM_FUNC_FLASH_FLUSH_CACHE      ROM_TABLE_CODE('F', 'C')
35 #define ROM_FUNC_FLASH_ENTER_CMD_XIP    ROM_TABLE_CODE('C', 'X')
36 
37 /*! \brief Return a bootrom lookup code based on two ASCII characters
38  * \ingroup pico_bootrom
39  *
40  * These codes are uses to lookup data or function addresses in the bootrom
41  *
42  * \param c1 the first character
43  * \param c2 the second character
44  * \return the 'code' to use in rom_func_lookup() or rom_data_lookup()
45  */
46 #define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8))
47 
48 #ifndef __ASSEMBLER__
49 
50 // ROM FUNCTION SIGNATURES
51 
52 typedef uint32_t (*rom_popcount32_fn)(uint32_t);
53 typedef uint32_t (*rom_reverse32_fn)(uint32_t);
54 typedef uint32_t (*rom_clz32_fn)(uint32_t);
55 typedef uint32_t (*rom_ctz32_fn)(uint32_t);
56 typedef uint8_t *(*rom_memset_fn)(uint8_t *, uint8_t, uint32_t);
57 typedef uint32_t *(*rom_memset4_fn)(uint32_t *, uint8_t, uint32_t);
58 typedef uint32_t *(*rom_memcpy_fn)(uint8_t *, const uint8_t *, uint32_t);
59 typedef uint32_t *(*rom_memcpy44_fn)(uint32_t *, const uint32_t *, uint32_t);
60 typedef void __attribute__((noreturn)) (*rom_reset_usb_boot_fn)(uint32_t, uint32_t);
61 typedef rom_reset_usb_boot_fn reset_usb_boot_fn; // kept for backwards compatibility
62 typedef void (*rom_connect_internal_flash_fn)(void);
63 typedef void (*rom_flash_exit_xip_fn)(void);
64 typedef void (*rom_flash_range_erase_fn)(uint32_t, size_t, uint32_t, uint8_t);
65 typedef void (*rom_flash_range_program_fn)(uint32_t, const uint8_t*, size_t);
66 typedef void (*rom_flash_flush_cache_fn)(void);
67 typedef void (*rom_flash_enter_cmd_xip_fn)(void);
68 
69 #ifdef __cplusplus
70 extern "C" {
71 #endif
72 
73 /*! \brief Return a bootrom lookup code based on two ASCII characters
74  * \ingroup pico_bootrom
75  *
76  * These codes are uses to lookup data or function addresses in the bootrom
77  *
78  * \param c1 the first character
79  * \param c2 the second character
80  * \return the 'code' to use in rom_func_lookup() or rom_data_lookup()
81  */
rom_table_code(uint8_t c1,uint8_t c2)82 static inline uint32_t rom_table_code(uint8_t c1, uint8_t c2) {
83     return ROM_TABLE_CODE((uint32_t) c1, (uint32_t) c2);
84 }
85 
86 /*!
87  * \brief Lookup a bootrom function by code
88  * \ingroup pico_bootrom
89  * \param code the code
90  * \return a pointer to the function, or NULL if the code does not match any bootrom function
91  */
92 void *rom_func_lookup(uint32_t code);
93 
94 /*!
95  * \brief Lookup a bootrom address by code
96  * \ingroup pico_bootrom
97  * \param code the code
98  * \return a pointer to the data, or NULL if the code does not match any bootrom function
99  */
100 void *rom_data_lookup(uint32_t code);
101 
102 /*!
103  * \brief Helper function to lookup the addresses of multiple bootrom functions
104  * \ingroup pico_bootrom
105  *
106  * This method looks up the 'codes' in the table, and convert each table entry to the looked up
107  * function pointer, if there is a function for that code in the bootrom.
108  *
109  * \param table an IN/OUT array, elements are codes on input, function pointers on success.
110  * \param count the number of elements in the table
111  * \return true if all the codes were found, and converted to function pointers, false otherwise
112  */
113 bool rom_funcs_lookup(uint32_t *table, unsigned int count);
114 
115 // Bootrom function: rom_table_lookup
116 // Returns the 32 bit pointer into the ROM if found or NULL otherwise.
117 typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
118 
119 #if defined(__GNUC__) && (__GNUC__ >= 12)
120 // Convert a 16 bit pointer stored at the given rom address into a 32 bit pointer
rom_hword_as_ptr(uint16_t rom_address)121 static inline void *rom_hword_as_ptr(uint16_t rom_address) {
122 #pragma GCC diagnostic push
123 #pragma GCC diagnostic ignored "-Warray-bounds"
124     return (void *)(uintptr_t)*(uint16_t *)(uintptr_t)rom_address;
125 #pragma GCC diagnostic pop
126 }
127 #else
128 // Convert a 16 bit pointer stored at the given rom address into a 32 bit pointer
129 #define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)(uintptr_t)(rom_address))
130 #endif
131 
132 /*!
133  * \brief Lookup a bootrom function by code. This method is forcibly inlined into the caller for FLASH/RAM sensitive code usage
134  * \ingroup pico_bootrom
135  * \param code the code
136  * \return a pointer to the function, or NULL if the code does not match any bootrom function
137  */
rom_func_lookup_inline(uint32_t code)138 static __force_inline void *rom_func_lookup_inline(uint32_t code) {
139     rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
140     uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
141     return rom_table_lookup(func_table, code);
142 }
143 
144 /*!
145  * \brief Reboot the device into BOOTSEL mode
146  * \ingroup pico_bootrom
147  *
148  * This function reboots the device into the BOOTSEL mode ('usb boot").
149  *
150  * Facilities are provided to enable an "activity light" via GPIO attached LED for the USB Mass Storage Device,
151  * and to limit the USB interfaces exposed.
152  *
153  * \param usb_activity_gpio_pin_mask 0 No pins are used as per a cold boot. Otherwise a single bit set indicating which
154  *                               GPIO pin should be set to output and raised whenever there is mass storage activity
155  *                               from the host.
156  * \param disable_interface_mask value to control exposed interfaces
157  *  - 0 To enable both interfaces (as per a cold boot)
158  *  - 1 To disable the USB Mass Storage Interface
159  *  - 2 To disable the USB PICOBOOT Interface
160  */
reset_usb_boot(uint32_t usb_activity_gpio_pin_mask,uint32_t disable_interface_mask)161 static inline void __attribute__((noreturn)) reset_usb_boot(uint32_t usb_activity_gpio_pin_mask,
162                                                             uint32_t disable_interface_mask) {
163     rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT);
164     func(usb_activity_gpio_pin_mask, disable_interface_mask);
165 }
166 
167 #ifdef __cplusplus
168 }
169 #endif
170 
171 #endif // !__ASSEMBLER__
172 #endif
173