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