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