1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-4-30 IceBear003 the first version adapted from CherryUSB
9 */
10
11 #include "board.h"
12 #include "drv_usbd.h"
13
14 #ifdef BSP_USING_USBD
15
16 #define LOG_TAG "drv.usbd"
17 #include "drv_log.h"
18
19 #define UEP_MPS_64 64
20 #define UEP_MPS_512 512
21
22 #define _get_ep_idx(address) ((address) & USB_EPNO_MASK)
23 #define _get_ep_dir(address) ((address) & USB_DIR_MASK)
24 #define _is_dir_in(address) (_get_ep_dir(address) == USB_DIR_IN)
25 #define _is_dir_out(address) (_get_ep_dir(address) == USB_DIR_OUT)
26
27 #define _get_dma(ep_idx) (*(volatile uint32_t *)((uint32_t)(USBFSD->UEP0_DMA) + 4 * ep_idx))
28 #define _set_dma(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(USBFSD->UEP0_DMA) + 4 * ep_idx) = addr)
29 #define _set_tx_len(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(USBFSD->UEP0_TX_LEN) + 4 * ep_idx) = len)
30 #define _get_tx_len(ep_idx) (*(volatile uint16_t *)((uint32_t)(USBFSD->UEP0_TX_LEN) + 4 * ep_idx))
31 #define _set_tx_ctrl(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(USBFSD->UEP0_TX_CTRL) + 4 * ep_idx) = val)
32 #define _get_tx_ctrl(ep_idx) (*(volatile uint8_t *)((uint32_t)(USBFSD->UEP0_TX_CTRL) + 4 * ep_idx))
33 #define _set_rx_ctrl(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(USBFSD->UEP0_RX_CTRL) + 4 * ep_idx) = val)
34 #define _get_rx_ctrl(ep_idx) (*(volatile uint8_t *)((uint32_t)(USBFSD->UEP0_RX_CTRL) + 4 * ep_idx))
35
36 static struct udcd udcd;
37
38 USBOTG_FS_TypeDef *USBFSD = USBOTG_FS;
39
40 static struct ep_id endpoint_pool[] =
41 {
42 {0x0, USB_EP_ATTR_CONTROL, USB_DIR_INOUT, 64, ID_ASSIGNED },
43 {0x1, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED},
44 {0x1, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED},
45 {0x2, USB_EP_ATTR_INT, USB_DIR_IN, 512, ID_UNASSIGNED},
46 {0x2, USB_EP_ATTR_INT, USB_DIR_OUT, 512, ID_UNASSIGNED},
47 {0x3, USB_EP_ATTR_ISOC, USB_DIR_IN, 512, ID_UNASSIGNED},
48 {0x3, USB_EP_ATTR_ISOC, USB_DIR_OUT, 512, ID_UNASSIGNED},
49 {0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
50 };
51
_uep_mod_get(uint8_t ep_idx)52 uint8_t _uep_mod_get(uint8_t ep_idx)
53 {
54 switch(ep_idx)
55 {
56 case 1:
57 case 4: return USBFSD->UEP4_1_MOD;
58 case 2:
59 case 3: return USBFSD->UEP2_3_MOD;
60 case 5:
61 case 6: return USBFSD->UEP5_6_MOD;
62 case 7: return USBFSD->UEP7_MOD;
63 default: return 0;
64 }
65 }
66
_uep_mod_set(uint8_t ep_idx,uint8_t value)67 rt_err_t _uep_mod_set(uint8_t ep_idx, uint8_t value)
68 {
69 switch(ep_idx)
70 {
71 case 1:
72 case 4: USBFSD->UEP4_1_MOD = value; break;
73 case 2:
74 case 3: USBFSD->UEP2_3_MOD = value; break;
75 case 5:
76 case 6: USBFSD->UEP5_6_MOD = value; break;
77 case 7: USBFSD->UEP7_MOD = value; break;
78 default: return -RT_ERROR;
79 }
80 return RT_EOK;
81 }
82
_uep_tx_en(uint8_t ep_idx)83 uint8_t _uep_tx_en(uint8_t ep_idx)
84 {
85 switch(ep_idx)
86 {
87 case 1: return USBFS_UEP1_TX_EN;
88 case 4: return USBFS_UEP4_TX_EN;
89 case 2: return USBFS_UEP2_TX_EN;
90 case 3: return USBFS_UEP3_TX_EN;
91 case 5: return USBFS_UEP5_TX_EN;
92 case 6: return USBFS_UEP6_TX_EN;
93 case 7: return USBFS_UEP7_TX_EN;
94 default: return 0;
95 }
96 }
97
_uep_rx_en(uint8_t ep_idx)98 uint8_t _uep_rx_en(uint8_t ep_idx)
99 {
100 switch(ep_idx)
101 {
102 case 1: return USBFS_UEP1_TX_EN;
103 case 4: return USBFS_UEP4_TX_EN;
104 case 2: return USBFS_UEP2_TX_EN;
105 case 3: return USBFS_UEP3_TX_EN;
106 case 5: return USBFS_UEP5_TX_EN;
107 case 6: return USBFS_UEP6_TX_EN;
108 case 7: return USBFS_UEP7_TX_EN;
109 default: return 0;
110 }
111 }
112
usbd_set_address(rt_uint8_t address)113 rt_err_t usbd_set_address(rt_uint8_t address)
114 {
115 if(address > 0x7f)
116 return -RT_ERROR;
117 USBFSD->DEV_ADDR = (USBFSD->DEV_ADDR & USBFS_UDA_GP_BIT) | address;
118 return RT_EOK;
119 }
120
usbd_set_config(rt_uint8_t address)121 rt_err_t usbd_set_config(rt_uint8_t address)
122 { //Nonsense?
123 return RT_EOK;
124 }
125
usbd_ep_set_stall(rt_uint8_t address)126 rt_err_t usbd_ep_set_stall(rt_uint8_t address)
127 {
128 uint8_t ep_idx = _get_ep_idx(address);
129
130 if (_is_dir_out(address))
131 if (ep_idx == 0)
132 _set_rx_ctrl(0, USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL);
133 else
134 _set_rx_ctrl(ep_idx, (_get_rx_ctrl(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_STALL);
135 else
136 if (ep_idx == 0)
137 _set_tx_ctrl(0, USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL);
138 else
139 _set_tx_ctrl(ep_idx, (_get_tx_ctrl(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_STALL);
140
141 return RT_EOK;
142 }
143
usbd_ep_clear_stall(rt_uint8_t address)144 rt_err_t usbd_ep_clear_stall(rt_uint8_t address)
145 {
146 uint8_t ep_idx = _get_ep_idx(address);
147
148 if (_is_dir_in(address))
149 _set_tx_ctrl(ep_idx, (_get_tx_ctrl(ep_idx) & ~(USBFS_UEP_T_TOG | USBFS_UEP_T_RES_MASK)) | USBFS_UEP_T_RES_NAK);
150 else
151 _set_rx_ctrl(ep_idx, (_get_rx_ctrl(ep_idx) & ~(USBFS_UEP_R_TOG | USBFS_UEP_R_RES_MASK)) | USBFS_UEP_R_RES_ACK);
152
153 return RT_EOK;
154 }
155
usbd_ep_enable(struct uendpoint * ep)156 rt_err_t usbd_ep_enable(struct uendpoint* ep)
157 {
158 RT_ASSERT(ep != RT_NULL);
159 RT_ASSERT(ep->ep_desc != RT_NULL);
160
161 uint8_t address = EP_ADDRESS(ep);
162 uint8_t ep_idx = _get_ep_idx(address);
163
164 if (ep_idx != 0)
165 {
166 uint8_t mod = _is_dir_in(address) ? _uep_tx_en(ep_idx) : _uep_rx_en(ep_idx);
167 mod = _uep_mod_get(ep_idx) | mod;
168 _uep_mod_set(ep_idx, mod);
169 } else return -RT_ERROR;
170
171 return RT_EOK;
172 }
173
usbd_ep_disable(struct uendpoint * ep)174 rt_err_t usbd_ep_disable(struct uendpoint* ep)
175 {
176 RT_ASSERT(ep != RT_NULL);
177 RT_ASSERT(ep->ep_desc != RT_NULL);
178
179 uint8_t address = EP_ADDRESS(ep);
180 uint8_t ep_idx = _get_ep_idx(address);
181
182 if (ep_idx != 0)
183 {
184 uint8_t mod = _is_dir_in(address) ? _uep_tx_en(ep_idx) : _uep_rx_en(ep_idx);
185 mod = _uep_mod_get(ep_idx) & ~mod;
186 _uep_mod_set(ep_idx, mod);
187 } else return -RT_ERROR;
188
189 return RT_EOK;
190 }
191
usbd_ep_read_prepare(rt_uint8_t address,void * buffer,rt_size_t size)192 rt_size_t usbd_ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size)
193 {
194 uint8_t ep_idx = _get_ep_idx(address);
195
196 if (_is_dir_in(address))
197 return 0;
198
199 if (size > (ep_idx ? UEP_MPS_512 : UEP_MPS_64))
200 size = (ep_idx ? UEP_MPS_512 : UEP_MPS_64);
201
202 _set_dma(ep_idx, (uint32_t)buffer);
203
204 if (ep_idx == 0)
205 if(size == 0) _set_rx_ctrl(0, USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG);
206 else _set_rx_ctrl(ep_idx, USBFS_UEP_R_RES_ACK);
207 else _set_rx_ctrl(0, (_get_rx_ctrl(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG);
208
209 return size;
210 }
211
usbd_ep_read(rt_uint8_t address,void * buffer)212 rt_size_t usbd_ep_read(rt_uint8_t address, void *buffer)
213 {
214 uint8_t ep_idx = _get_ep_idx(address);
215
216 if (_is_dir_out(address))
217 return -2;
218 if ((uint32_t)buffer & 0x03)
219 return -3;
220
221 uint32_t dmabuf = _get_dma(ep_idx);
222 rt_size_t size = USBFSD->RX_LEN;
223
224 if (size > 0 && (uint32_t)buffer != dmabuf)
225 rt_memcpy(buffer, (void *)dmabuf, size);
226
227 return size;
228 }
229
usbd_ep_write(rt_uint8_t address,void * buffer,rt_size_t size)230 rt_size_t usbd_ep_write(rt_uint8_t address, void *buffer, rt_size_t size)
231 {
232 uint8_t ep_idx = _get_ep_idx(address);
233
234 if (_is_dir_in(address))
235 return -2;
236 if ((uint32_t)buffer & 0x03)
237 return -3;
238
239 uint32_t dmabuf = _get_dma(ep_idx);
240
241 if (size > (ep_idx ? UEP_MPS_512 : UEP_MPS_64))
242 size = (ep_idx ? UEP_MPS_512 : UEP_MPS_64);
243
244 _set_tx_len(ep_idx, size);
245 if(ep_idx == 0)
246 {
247 if(size != 0)
248 _set_dma(0, (uint32_t)buffer);
249 _set_tx_ctrl(0, USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK);
250 }
251 else
252 {
253 if(size != 0)
254 rt_memcpy((void *)dmabuf, buffer, size);
255 _set_tx_ctrl(ep_idx, (_get_tx_ctrl(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK);
256 }
257
258 return size;
259 }
260
usbd_ep0_send_status(void)261 rt_err_t usbd_ep0_send_status(void)
262 {
263 _set_tx_len(0, 0);
264 _set_tx_ctrl(0, USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG);
265 _set_dma(0, 0);
266 return RT_EOK;
267 }
268
usbd_suspend(void)269 rt_err_t usbd_suspend(void)
270 {
271 return RT_EOK;
272 }
273
usbd_wakeup(void)274 rt_err_t usbd_wakeup(void)
275 {
276 return RT_EOK;
277 }
278
279 const struct udcd_ops udcd_ops =
280 {
281 .set_address = usbd_set_address,
282 .set_config = usbd_set_config,
283 .ep_set_stall = usbd_ep_set_stall,
284 .ep_clear_stall = usbd_ep_clear_stall,
285 .ep_enable = usbd_ep_enable,
286 .ep_disable = usbd_ep_disable,
287 .ep_read_prepare = usbd_ep_read_prepare,
288 .ep_read = usbd_ep_read,
289 .ep_write = usbd_ep_write,
290 .ep0_send_status = usbd_ep0_send_status,
291 .suspend = usbd_suspend,
292 .wakeup = usbd_wakeup,
293 };
294
dcd_init(rt_device_t dev)295 rt_err_t dcd_init(rt_device_t dev)
296 {
297 USBFSD->BASE_CTRL = 0x00;
298
299 USBFSD->UEP4_1_MOD = USBFS_UEP4_RX_EN | USBFS_UEP4_TX_EN | USBFS_UEP1_RX_EN | USBFS_UEP1_TX_EN;
300 USBFSD->UEP2_3_MOD = USBFS_UEP2_RX_EN | USBFS_UEP2_TX_EN | USBFS_UEP3_RX_EN | USBFS_UEP3_TX_EN;
301 USBFSD->UEP5_6_MOD = USBFS_UEP5_RX_EN | USBFS_UEP5_TX_EN | USBFS_UEP6_RX_EN | USBFS_UEP6_TX_EN;
302 USBFSD->UEP7_MOD = USBFS_UEP7_RX_EN | USBFS_UEP7_TX_EN;
303
304 USBFSD->INT_FG = 0xFF;
305 USBFSD->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_BUS_RST | USBFS_UIE_TRANSFER;
306 USBFSD->DEV_ADDR = 0x00;
307
308 USBFSD->BASE_CTRL = USBFS_UC_DEV_PU_EN | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
309 USBFSD->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN;
310
311 NVIC_EnableIRQ(OTG_FS_IRQn);
312
313 return RT_EOK;
314 }
315
316 void USBD_IRQHandler(void) __attribute__((interrupt()));
USBD_IRQHandler()317 void USBD_IRQHandler()
318 {
319 rt_interrupt_enter();
320 uint8_t int_fg = USBFSD->INT_FG;
321
322 if (int_fg & USBFS_UIF_TRANSFER) {
323 uint8_t ep_idx = USBFSD->INT_ST & USBFS_UIS_ENDP_MASK;
324 uint8_t tog;
325 switch (USBFSD->INT_ST & USBFS_UIS_TOKEN_MASK) {
326 case USBFS_UIS_TOKEN_SETUP:
327 _set_rx_ctrl(ep_idx, USBFS_UEP_R_RES_NAK);
328 break;
329
330 case USBFS_UIS_TOKEN_IN:
331 if (ep_idx == 0x00)
332 {
333 tog = _get_tx_ctrl(ep_idx) & USBFS_UEP_T_TOG;
334 _set_tx_ctrl(ep_idx, (_get_tx_ctrl(ep_idx) & 0b11111000) | ~tog | USBFS_UEP_T_RES_NAK);
335 if (_get_dma(ep_idx) != 0)
336 {
337 rt_usbd_ep0_in_handler(&udcd);
338 }
339 }
340 else
341 {
342 _set_tx_ctrl(ep_idx, (_get_tx_ctrl(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NAK);
343 rt_usbd_ep_in_handler(&udcd, ep_idx | USB_DIR_IN, _get_tx_len(ep_idx));
344 }
345 break;
346 case USBFS_UIS_TOKEN_OUT:
347 if (ep_idx == 0x00)
348 {
349 if(USBFSD->INT_ST & USBFS_UIS_TOG_OK)
350 {
351 tog = _get_rx_ctrl(ep_idx) & USBFS_UEP_R_TOG;
352 _set_rx_ctrl(ep_idx, (_get_rx_ctrl(ep_idx) & 0b11111000) | ~tog | USBFS_UEP_R_RES_NAK);
353 }
354 else
355 {
356 _set_rx_ctrl(ep_idx, (_get_rx_ctrl(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK);
357 }
358 }
359 else
360 {
361 _set_rx_ctrl(ep_idx, (_get_rx_ctrl(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK);
362 if (USBFSD->INT_ST & USBFS_UIS_TOG_OK) {
363 _set_rx_ctrl(ep_idx, (_get_rx_ctrl(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK);
364 rt_usbd_ep_out_handler(&udcd, ep_idx | USB_DIR_OUT, 0);
365 }
366 }
367 break;
368 default:
369 break;
370 }
371
372 USBFSD->INT_FG = USBFS_UIF_TRANSFER;
373 } else if (int_fg & USBFS_UIF_BUS_RST) {
374 USBFSD->UEP0_TX_LEN = 0;
375 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
376 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
377
378 for (uint8_t i = 1; i < 8; i++) {
379 _set_tx_len(i, 0);
380 _set_tx_ctrl(i, USBFS_UEP_T_RES_NAK | USBFS_UEP_T_AUTO_TOG);
381 _set_rx_ctrl(i, USBFS_UEP_R_RES_NAK | USBFS_UEP_R_AUTO_TOG);
382 }
383
384 _set_rx_ctrl(0, USBFS_UEP_R_RES_ACK);
385 rt_usbd_reset_handler(&udcd);
386
387 USBFSD->INT_FG |= USBFS_UIF_BUS_RST;
388 } else if (int_fg & USBFS_UIF_SUSPEND) {
389 USBFSD->INT_FG = USBFS_UIF_SUSPEND;
390 } else {
391 USBFSD->INT_FG = int_fg;
392 }
393
394 rt_interrupt_leave();
395 }
396
rt_hw_usbd_init()397 int rt_hw_usbd_init()
398 {
399 rt_err_t res = -RT_ERROR;
400
401 rt_memset((void *)&udcd, 0, sizeof(struct uhcd));
402 udcd.parent.type = RT_Device_Class_USBDevice;
403 udcd.parent.user_data = (void *)USBFS_BASE;
404 udcd.parent.init = dcd_init;
405 udcd.ops = &udcd_ops;
406 udcd.ep_pool = endpoint_pool;
407 udcd.ep0.id = &endpoint_pool[0];
408 udcd.device_is_hs = RT_FALSE;
409
410 res = rt_device_register(&udcd.parent, "usbd", RT_DEVICE_FLAG_DEACTIVATE);
411
412 if (res != RT_EOK)
413 {
414 rt_kprintf("register usb device failed res = %d\r\n", res);
415 return -RT_ERROR;
416 }
417
418 rt_usb_device_init();
419
420 return RT_EOK;
421 }
422 #endif //BSP_USING_USBD
423