1 /*
2 * SPDX-FileCopyrightText: 2016 Cesanta Software Limited
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
7 */
8
9 #include <stdlib.h>
10 #include "stub_io.h"
11 #include "rom_functions.h"
12 #include "soc_support.h"
13
14
15 #define UART_RX_INTS (UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA)
16
17
18 static void(*s_rx_cb_func)(char);
19 #ifdef WITH_USB_OTG
20 static uint32_t s_cdcacm_old_rts;
21 static volatile bool s_cdcacm_reset_requested;
22 static char s_cdcacm_txbuf[ACM_BYTES_PER_TX];
23 static size_t s_cdcacm_txpos;
24 #endif // WITH_USB_OTG
25
26
uart_isr(void * arg)27 void uart_isr(void *arg) {
28 uint32_t int_st = READ_REG(UART_INT_ST(0));
29 while (1) {
30 uint32_t fifo_len = READ_REG(UART_STATUS(0)) & UART_RXFIFO_CNT_M;
31 if (fifo_len == 0) {
32 break;
33 }
34 while (fifo_len-- > 0) {
35 uint8_t byte = READ_REG(UART_FIFO(0)) & 0xff;
36 (*s_rx_cb_func)(byte);
37 }
38 }
39 WRITE_REG(UART_INT_CLR(0), int_st);
40 }
41
42 #if WITH_USB_JTAG_SERIAL
stub_uses_usb_jtag_serial(void)43 bool stub_uses_usb_jtag_serial(void)
44 {
45 UartDevice *uart = GetUartDevice();
46
47 /* buff_uart_no indicates which UART is used for SLIP communication) */
48 return uart->buff_uart_no == UART_USB_JTAG_SERIAL;
49 }
50
jtag_serial_isr(void * arg)51 void jtag_serial_isr(void *arg)
52 {
53 WRITE_REG(USB_DEVICE_INT_CLR_REG, USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_CLR); //ack interrupt
54 while (READ_REG(USB_DEVICE_EP1_CONF_REG) & USB_DEVICE_SERIAL_OUT_EP_DATA_AVAIL)
55 {
56 uint8_t byte = READ_REG(USB_DEVICE_EP1_REG);
57 (*s_rx_cb_func)(byte);
58 }
59 }
60 #endif // WITH_USB_JTAG_SERIAL
61
stub_configure_rx_uart(void)62 static void stub_configure_rx_uart(void)
63 {
64 /* All UART reads come via uart_isr or jtag_serial_isr */
65 #if WITH_USB_JTAG_SERIAL
66 if (stub_uses_usb_jtag_serial()) {
67 #if IS_RISCV
68 #if ESP32P4
69 WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM + CLIC_EXT_INTR_NUM_OFFSET);
70 #else
71 WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM); // Route USB interrupt to CPU
72 #endif
73 esprv_intc_int_set_priority(ETS_USB_INUM, 1);
74 #else
75 WRITE_REG(INTERRUPT_CORE0_USB_DEVICE_INT_MAP_REG, ETS_USB_INUM);
76 #endif // IS_RISCV
77 ets_isr_attach(ETS_USB_INUM, jtag_serial_isr, NULL);
78 WRITE_REG(USB_DEVICE_INT_ENA_REG, USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_ENA);
79 ets_isr_unmask(1 << ETS_USB_INUM);
80 return;
81 }
82 #endif // WITH_USB_JTAG_SERIAL
83 ets_isr_attach(ETS_UART0_INUM, uart_isr, NULL);
84 REG_SET_MASK(UART_INT_ENA(0), UART_RX_INTS);
85 ets_isr_unmask(1 << ETS_UART0_INUM);
86 }
87
88 #ifdef WITH_USB_OTG
89
stub_cdcacm_cb(cdc_acm_device * dev,int status)90 void stub_cdcacm_cb(cdc_acm_device *dev, int status)
91 {
92 if (status == ACM_STATUS_RX) {
93 while (cdc_acm_rx_fifo_cnt(uart_acm_dev) > 0) {
94 uint8_t c;
95 cdc_acm_fifo_read(uart_acm_dev, &c, 1);
96 (*s_rx_cb_func)((char) c);
97 }
98 } else if (status == ACM_STATUS_LINESTATE_CHANGED) {
99 uint32_t rts = 0;
100 cdc_acm_line_ctrl_get(dev, LINE_CTRL_RTS, &rts);
101 if (rts == 0 && s_cdcacm_old_rts == 1) {
102 s_cdcacm_reset_requested = true;
103 }
104 s_cdcacm_old_rts = rts;
105 }
106 }
107
stub_cdcacm_flush(void)108 static void stub_cdcacm_flush(void)
109 {
110 cdc_acm_fifo_fill(uart_acm_dev, (const uint8_t *) s_cdcacm_txbuf, s_cdcacm_txpos);
111 /* return value ignored — if bootloader fails to log something, proceed anyway */
112 s_cdcacm_txpos = 0;
113 }
114
stub_cdcacm_write_char(char ch)115 static void stub_cdcacm_write_char(char ch)
116 {
117 s_cdcacm_txbuf[s_cdcacm_txpos++] = ch;
118 if (ch == '\xc0' || s_cdcacm_txpos == sizeof(s_cdcacm_txbuf)) {
119 stub_cdcacm_flush();
120 }
121 }
122
stub_uses_usb_otg(void)123 bool stub_uses_usb_otg(void)
124 {
125 UartDevice *uart = GetUartDevice();
126
127 /* buff_uart_no indicates which UART is used for SLIP communication) */
128 return uart->buff_uart_no == UART_USB_OTG;
129 }
130
131 #ifdef ESP32S3
usb_dw_isr_handler_wrapper(void * arg)132 static void usb_dw_isr_handler_wrapper(void *arg)
133 {
134 /* ISR handler wrapper added as a workaround for the failure of compressed flashing using USB OTG.
135 *
136 * LoadStoreException happens inside the first call of tinfl_decompress() where the a13 register gets corrupted by
137 * the address of usb_dw_isr_handler(). The corruption probably still happens with this workaround but because of
138 * the nested call another register window is used.
139 *
140 * Other possible workarounds:
141 * - wait at least 25 ms before the tinfl_decompress() so usb_dw_isr_handler() would finish and not corrupt the
142 * pointer inside of tinfl_decompress(), or
143 * - disable the USB interrupt during tinfl_decompress().
144 */
145 usb_dw_isr_handler(arg);
146 }
147 #else
148 #define usb_dw_isr_handler_wrapper usb_dw_isr_handler
149 #endif //ESP32S3
150
stub_configure_rx_usb(void)151 static void stub_configure_rx_usb(void)
152 {
153 cdc_acm_line_ctrl_get(uart_acm_dev, LINE_CTRL_RTS, &s_cdcacm_old_rts);
154 #if ESP32S2
155 intr_matrix_set(0, ETS_USB_INTR_SOURCE, ETS_USB_INUM);
156 #elif ESP32S3
157 WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM);
158 #endif
159 ets_isr_attach(ETS_USB_INUM, usb_dw_isr_handler_wrapper, NULL);
160 ets_isr_unmask(1 << ETS_USB_INUM);
161 cdc_acm_irq_callback_set(uart_acm_dev, &stub_cdcacm_cb);
162 cdc_acm_irq_rx_enable(uart_acm_dev);
163 cdc_acm_irq_state_enable(uart_acm_dev);
164 REG_SET_MASK(USB_GAHBCFG_REG, USB_GLBLLNTRMSK);
165 }
166 #endif // WITH_USB_OTG
167
stub_tx_one_char(char c)168 void stub_tx_one_char(char c)
169 {
170 #if WITH_USB_OTG
171 if (stub_uses_usb_otg()) {
172 stub_cdcacm_write_char(c);
173 return;
174 }
175 #endif // WITH_USB_OTG
176 uart_tx_one_char(c);
177 #if WITH_USB_JTAG_SERIAL
178 static unsigned short transferred_without_flush = 0;
179 if (stub_uses_usb_jtag_serial()){
180 // Defer flushing until we have a (full - 1) packet or a end of packet (0xc0) byte to increase throughput.
181 // Note that deferring flushing until we have a full packet can cause hang-ups on some platforms.
182 ++transferred_without_flush;
183 if (c == '\xc0' || transferred_without_flush >= 63) {
184 stub_tx_flush();
185 transferred_without_flush = 0;
186 }
187 }
188 #endif // WITH_USB_JTAG_SERIAL
189 }
190
stub_tx_flush(void)191 void stub_tx_flush(void)
192 {
193 #if WITH_USB_OTG
194 if (stub_uses_usb_otg()) {
195 if (s_cdcacm_txpos > 0) {
196 stub_cdcacm_flush();
197 }
198 }
199 #endif // WITH_USB_OTG
200 #if WITH_USB_JTAG_SERIAL
201 if (stub_uses_usb_jtag_serial()){
202 uart_tx_flush(UART_USB_JTAG_SERIAL);
203 return;
204 }
205 #endif // WITH_USB_JTAG_SERIAL
206 #if ESP32_OR_LATER
207 uart_tx_flush(0);
208 #endif
209 }
210
stub_rx_one_char(void)211 char stub_rx_one_char(void)
212 {
213 char c = 0;
214 /* Using uart_rx_one_char here instead of uart_rx_one_char_block,
215 * because the latter simply returns (char) 0 if no bytes
216 * are available, when used with USB CDC.
217 */
218 while (uart_rx_one_char((uint8_t*) &c) != 0) { }
219 return c;
220 }
221
stub_rx_async_enable(bool enable)222 void stub_rx_async_enable(bool enable)
223 {
224 uint32_t mask;
225 #if WITH_USB_OTG
226 if (stub_uses_usb_otg()) {
227 mask = 1 << ETS_USB_INUM;
228 if (enable) {
229 cdc_acm_irq_rx_enable(uart_acm_dev);
230 ets_isr_unmask(mask);
231 } else {
232 ets_isr_mask(mask);
233 cdc_acm_irq_rx_disable(uart_acm_dev);
234 }
235 return;
236 }
237 #endif // WITH_USB_OTG
238 #if WITH_USB_JTAG_SERIAL
239 mask = stub_uses_usb_jtag_serial() ? 1 << ETS_USB_INUM : 1 << ETS_UART0_INUM;
240 #else
241 mask = 1 << ETS_UART0_INUM;
242 #endif
243 if (enable) {
244 ets_isr_unmask(mask);
245 } else {
246 ets_isr_mask(mask);
247 }
248 }
249
stub_io_idle_hook(void)250 void stub_io_idle_hook(void)
251 {
252 #if WITH_USB_OTG
253 if (s_cdcacm_reset_requested)
254 {
255 s_cdcacm_reset_requested = false;
256 ets_isr_mask(1 << ETS_USB_INUM);
257 ets_delay_us(10000);
258 /* Handle the last few interrupts as they come in before the USB peripheral is idle */
259 usb_dc_check_poll_for_interrupts();
260 REG_CLR_MASK(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
261 chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
262 usb_dc_prepare_persist();
263 software_reset_cpu(0);
264 }
265 #endif // WITH_USB_OTG
266 }
267
stub_io_init(void (* rx_cb_func)(char))268 void stub_io_init(void(*rx_cb_func)(char))
269 {
270 s_rx_cb_func = rx_cb_func;
271 #if WITH_USB_OTG
272 if (stub_uses_usb_otg()) {
273 stub_configure_rx_usb();
274 return;
275 }
276 #endif // WITH_USB_OTG
277 stub_configure_rx_uart();
278 }
279
get_new_uart_divider(uint32_t current_baud,uint32_t new_baud)280 static uint32_t get_new_uart_divider(uint32_t current_baud, uint32_t new_baud)
281 {
282 uint32_t master_freq;
283 /* ESP32 has ROM code to detect the crystal freq but ESP8266 does not have this...
284 So instead we use the previously auto-synced 115200 baud rate (which we know
285 is correct wrt the relative crystal accuracy of the ESP & the USB/serial adapter).
286 From this we can estimate crystal freq, and update for a new baud rate relative to that.
287 */
288 uint32_t uart_reg = READ_REG(UART_CLKDIV_REG(0));
289 uint32_t uart_div = uart_reg & UART_CLKDIV_M;
290 #if ESP32_OR_LATER
291 // account for fractional part of divider (bottom 4 bits)
292 uint32_t fraction = (uart_reg >> UART_CLKDIV_FRAG_S) & UART_CLKDIV_FRAG_V;
293 uart_div = (uart_div << 4) + fraction;
294 #endif
295 master_freq = uart_div * current_baud;
296 return master_freq / new_baud;
297 }
298
stub_io_set_baudrate(uint32_t current_baud,uint32_t new_baud)299 void stub_io_set_baudrate(uint32_t current_baud, uint32_t new_baud)
300 {
301 #if WITH_USB_OTG
302 /* Technically no harm in increasing UART baud rate when communicating over USB,
303 * however for debugging the USB part it is occasionally useful to ets_printf
304 * something to UART. Not changing the baud rate helps in such case.
305 */
306 if (stub_uses_usb_otg()) {
307 return;
308 }
309 #endif // WITH_USB_OTG
310 ets_delay_us(10000);
311 uart_div_modify(0, get_new_uart_divider(current_baud, new_baud));
312 ets_delay_us(1000);
313 }
314