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 WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM); // Route USB interrupt to CPU
69 esprv_intc_int_set_priority(ETS_USB_INUM, 1);
70 #else
71 WRITE_REG(INTERRUPT_CORE0_USB_DEVICE_INT_MAP_REG, ETS_USB_INUM);
72 #endif // IS_RISCV
73 ets_isr_attach(ETS_USB_INUM, jtag_serial_isr, NULL);
74 REG_SET_MASK(USB_DEVICE_INT_ENA_REG, USB_DEVICE_SERIAL_OUT_RECV_PKT_INT_ENA);
75 ets_isr_unmask(1 << ETS_USB_INUM);
76 return;
77 }
78 #endif // WITH_USB_JTAG_SERIAL
79 ets_isr_attach(ETS_UART0_INUM, uart_isr, NULL);
80 REG_SET_MASK(UART_INT_ENA(0), UART_RX_INTS);
81 ets_isr_unmask(1 << ETS_UART0_INUM);
82 }
83
84 #ifdef WITH_USB_OTG
85
stub_cdcacm_cb(cdc_acm_device * dev,int status)86 void stub_cdcacm_cb(cdc_acm_device *dev, int status)
87 {
88 if (status == ACM_STATUS_RX) {
89 while (cdc_acm_rx_fifo_cnt(uart_acm_dev) > 0) {
90 uint8_t c;
91 cdc_acm_fifo_read(uart_acm_dev, &c, 1);
92 (*s_rx_cb_func)((char) c);
93 }
94 } else if (status == ACM_STATUS_LINESTATE_CHANGED) {
95 uint32_t rts = 0;
96 cdc_acm_line_ctrl_get(dev, LINE_CTRL_RTS, &rts);
97 if (rts == 0 && s_cdcacm_old_rts == 1) {
98 s_cdcacm_reset_requested = true;
99 }
100 s_cdcacm_old_rts = rts;
101 }
102 }
103
stub_cdcacm_flush(void)104 static void stub_cdcacm_flush(void)
105 {
106 cdc_acm_fifo_fill(uart_acm_dev, (const uint8_t *) s_cdcacm_txbuf, s_cdcacm_txpos);
107 /* return value ignored — if bootloader fails to log something, proceed anyway */
108 s_cdcacm_txpos = 0;
109 }
110
stub_cdcacm_write_char(char ch)111 static void stub_cdcacm_write_char(char ch)
112 {
113 s_cdcacm_txbuf[s_cdcacm_txpos++] = ch;
114 if (ch == '\xc0' || s_cdcacm_txpos == sizeof(s_cdcacm_txbuf)) {
115 stub_cdcacm_flush();
116 }
117 }
118
stub_uses_usb_otg(void)119 bool stub_uses_usb_otg(void)
120 {
121 UartDevice *uart = GetUartDevice();
122
123 /* buff_uart_no indicates which UART is used for SLIP communication) */
124 return uart->buff_uart_no == UART_USB_OTG;
125 }
126
127 #ifdef ESP32S3
usb_dw_isr_handler_wrapper(void * arg)128 static void usb_dw_isr_handler_wrapper(void *arg)
129 {
130 /* ISR handler wrapper added as a workaround for the failure of compressed flashing using USB OTG.
131 *
132 * LoadStoreException happens inside the first call of tinfl_decompress() where the a13 register gets corrupted by
133 * the address of usb_dw_isr_handler(). The corruption probably still happens with this workaround but because of
134 * the nested call another register window is used.
135 *
136 * Other possible workarounds:
137 * - wait at least 25 ms before the tinfl_decompress() so usb_dw_isr_handler() would finish and not corrupt the
138 * pointer inside of tinfl_decompress(), or
139 * - disable the USB interrupt during tinfl_decompress().
140 */
141 usb_dw_isr_handler(arg);
142 }
143 #else
144 #define usb_dw_isr_handler_wrapper usb_dw_isr_handler
145 #endif //ESP32S3
146
stub_configure_rx_usb(void)147 static void stub_configure_rx_usb(void)
148 {
149 cdc_acm_line_ctrl_get(uart_acm_dev, LINE_CTRL_RTS, &s_cdcacm_old_rts);
150 #if ESP32S2
151 intr_matrix_set(0, ETS_USB_INTR_SOURCE, ETS_USB_INUM);
152 #elif ESP32S3
153 WRITE_REG(INTERRUPT_CORE0_USB_INTR_MAP_REG, ETS_USB_INUM);
154 #endif
155 ets_isr_attach(ETS_USB_INUM, usb_dw_isr_handler_wrapper, NULL);
156 ets_isr_unmask(1 << ETS_USB_INUM);
157 cdc_acm_irq_callback_set(uart_acm_dev, &stub_cdcacm_cb);
158 cdc_acm_irq_rx_enable(uart_acm_dev);
159 cdc_acm_irq_state_enable(uart_acm_dev);
160 REG_SET_MASK(USB_GAHBCFG_REG, USB_GLBLLNTRMSK);
161 }
162 #endif // WITH_USB_OTG
163
stub_tx_one_char(char c)164 void stub_tx_one_char(char c)
165 {
166 #if WITH_USB_OTG
167 if (stub_uses_usb_otg()) {
168 stub_cdcacm_write_char(c);
169 return;
170 }
171 #endif // WITH_USB_OTG
172 uart_tx_one_char(c);
173 #if WITH_USB_JTAG_SERIAL
174 if (stub_uses_usb_jtag_serial()){
175 stub_tx_flush();
176 }
177 #endif // WITH_USB_JTAG_SERIAL
178 }
179
stub_tx_flush(void)180 void stub_tx_flush(void)
181 {
182 #if WITH_USB_OTG
183 if (stub_uses_usb_otg()) {
184 if (s_cdcacm_txpos > 0) {
185 stub_cdcacm_flush();
186 }
187 }
188 #endif // WITH_USB_OTG
189 #if WITH_USB_JTAG_SERIAL
190 if (stub_uses_usb_jtag_serial()){
191 uart_tx_flush(UART_USB_JTAG_SERIAL);
192 return;
193 }
194 #endif // WITH_USB_JTAG_SERIAL
195 #if ESP32_OR_LATER
196 uart_tx_flush(0);
197 #endif
198 }
199
stub_rx_one_char(void)200 char stub_rx_one_char(void)
201 {
202 char c = 0;
203 /* Using uart_rx_one_char here instead of uart_rx_one_char_block,
204 * because the latter simply returns (char) 0 if no bytes
205 * are available, when used with USB CDC.
206 */
207 while (uart_rx_one_char((uint8_t*) &c) != 0) { }
208 return c;
209 }
210
stub_rx_async_enable(bool enable)211 void stub_rx_async_enable(bool enable)
212 {
213 uint32_t mask;
214 #if WITH_USB_OTG
215 if (stub_uses_usb_otg()) {
216 mask = 1 << ETS_USB_INUM;
217 if (enable) {
218 cdc_acm_irq_rx_enable(uart_acm_dev);
219 ets_isr_unmask(mask);
220 } else {
221 ets_isr_mask(mask);
222 cdc_acm_irq_rx_disable(uart_acm_dev);
223 }
224 return;
225 }
226 #endif // WITH_USB_OTG
227 #if WITH_USB_JTAG_SERIAL
228 mask = stub_uses_usb_jtag_serial() ? 1 << ETS_USB_INUM : 1 << ETS_UART0_INUM;
229 #else
230 mask = 1 << ETS_UART0_INUM;
231 #endif
232 if (enable) {
233 ets_isr_unmask(mask);
234 } else {
235 ets_isr_mask(mask);
236 }
237 }
238
stub_io_idle_hook(void)239 void stub_io_idle_hook(void)
240 {
241 #if WITH_USB_OTG
242 if (s_cdcacm_reset_requested)
243 {
244 s_cdcacm_reset_requested = false;
245 ets_isr_mask(1 << ETS_USB_INUM);
246 ets_delay_us(10000);
247 /* Handle the last few interrupts as they come in before the USB peripheral is idle */
248 usb_dc_check_poll_for_interrupts();
249 REG_CLR_MASK(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
250 chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
251 usb_dc_prepare_persist();
252 software_reset_cpu(0);
253 }
254 #endif // WITH_USB_OTG
255 }
256
stub_io_init(void (* rx_cb_func)(char))257 void stub_io_init(void(*rx_cb_func)(char))
258 {
259 s_rx_cb_func = rx_cb_func;
260 #if WITH_USB_OTG
261 if (stub_uses_usb_otg()) {
262 stub_configure_rx_usb();
263 return;
264 }
265 #endif // WITH_USB_OTG
266 stub_configure_rx_uart();
267 }
268
get_new_uart_divider(uint32_t current_baud,uint32_t new_baud)269 static uint32_t get_new_uart_divider(uint32_t current_baud, uint32_t new_baud)
270 {
271 uint32_t master_freq;
272 /* ESP32 has ROM code to detect the crystal freq but ESP8266 does not have this...
273 So instead we use the previously auto-synced 115200 baud rate (which we know
274 is correct wrt the relative crystal accuracy of the ESP & the USB/serial adapter).
275 From this we can estimate crystal freq, and update for a new baud rate relative to that.
276 */
277 uint32_t uart_reg = READ_REG(UART_CLKDIV_REG(0));
278 uint32_t uart_div = uart_reg & UART_CLKDIV_M;
279 #if ESP32_OR_LATER
280 // account for fractional part of divider (bottom 4 bits)
281 uint32_t fraction = (uart_reg >> UART_CLKDIV_FRAG_S) & UART_CLKDIV_FRAG_V;
282 uart_div = (uart_div << 4) + fraction;
283 #endif
284 master_freq = uart_div * current_baud;
285 return master_freq / new_baud;
286 }
287
stub_io_set_baudrate(uint32_t current_baud,uint32_t new_baud)288 void stub_io_set_baudrate(uint32_t current_baud, uint32_t new_baud)
289 {
290 #if WITH_USB_OTG
291 /* Technically no harm in increasing UART baud rate when communicating over USB,
292 * however for debugging the USB part it is occasionally useful to ets_printf
293 * something to UART. Not changing the baud rate helps in such case.
294 */
295 if (stub_uses_usb_otg()) {
296 return;
297 }
298 #endif // WITH_USB_OTG
299 ets_delay_us(10000);
300 uart_div_modify(0, get_new_uart_divider(current_baud, new_baud));
301 ets_delay_us(1000);
302 }
303