blob: 0cb78b5a50748378cbed64001b02533ab5f032dd [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <reg.h>
24#include <trace.h>
25#include <debug.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <assert.h>
30#include <err.h>
31#include <dev/usb.h>
32#include <dev/usbc.h>
33#include <arch/arm/cm.h>
34#include <platform/stm32.h>
35
36#define LOCAL_TRACE 0
37
38#define NUM_EP 5
39
40struct ep_status {
41 usbc_transfer_t *transfer;
42};
43
44static struct {
45 bool do_resched;
46
47 struct ep_status ep_in[NUM_EP];
48 struct ep_status ep_out[NUM_EP];
49
50 PCD_HandleTypeDef handle;
51} usbc;
52
53void stm32_usbc_early_init(void)
54{
55 __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
56}
57
58void stm32_usbc_init(void)
59{
60 LTRACE_ENTRY;
61
62 /* Set LL Driver parameters */
63 usbc.handle.Instance = USB_OTG_FS;
64 usbc.handle.Init.dev_endpoints = 4;
65 usbc.handle.Init.use_dedicated_ep1 = 0;
66 usbc.handle.Init.ep0_mps = 0x40;
67 usbc.handle.Init.dma_enable = 0;
68 usbc.handle.Init.low_power_enable = 1;
69 usbc.handle.Init.phy_itface = PCD_PHY_EMBEDDED;
70 usbc.handle.Init.Sof_enable = 0;
71 usbc.handle.Init.speed = PCD_SPEED_FULL;
72 usbc.handle.Init.vbus_sensing_enable = 0;
73 usbc.handle.Init.lpm_enable = 0;
74
75 /* Link The driver to the stack */
76 //usbc.handle.pData = pdev;
77 //pdev->pData = &hpcd;
78
79 /* Initialize LL Driver */
80 HAL_PCD_Init(&usbc.handle);
81
82 HAL_PCDEx_SetRxFiFo(&usbc.handle, 0x80);
83 HAL_PCDEx_SetTxFiFo(&usbc.handle, 0, 0x40);
84
85 HAL_PCD_EP_Open(&usbc.handle, 0, 0x40, EP_TYPE_CTRL);
86 HAL_PCD_EP_Open(&usbc.handle, 0x80, 0x40, EP_TYPE_CTRL);
87}
88
89void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
90{
91 LTRACEF("epnum %u\n", epnum);
92
93 if (usbc.ep_out[epnum].transfer) {
94 // completing a transfer
95 usbc_transfer_t *t = usbc.ep_out[epnum].transfer;
96 usbc.ep_out[epnum].transfer = NULL;
97
98 LTRACEF("completing transfer %p\n", t);
99
100 PCD_EPTypeDef *ep = &hpcd->OUT_ep[epnum];
101 t->bufpos = ep->xfer_count;
102 t->result = 0;
103 t->callback(epnum, t);
104 }
105}
106
107void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
108{
109 PCD_EPTypeDef *ep = &hpcd->IN_ep[epnum];
110
111 LTRACEF("epnum %u, xfer count %u len %u\n", epnum, ep->xfer_count, ep->xfer_len);
112
113 if (epnum == 0) {
114 if (ep->xfer_count >= ep->xfer_len) {
115 // in transfer done, ready for receive status
116 HAL_PCD_EP_Receive(&usbc.handle, 0, 0, 0);
117 } else {
118 PANIC_UNIMPLEMENTED;
119 }
120 } else {
121 // in transfer done
122 if (usbc.ep_in[epnum].transfer) {
123 // completing a transfer
124 usbc_transfer_t *t = usbc.ep_in[epnum].transfer;
125 usbc.ep_in[epnum].transfer = NULL;
126
127 LTRACEF("completing transfer %p\n", t);
128
129 PCD_EPTypeDef *ep = &hpcd->IN_ep[epnum];
130 t->bufpos = ep->xfer_count;
131 t->result = 0;
132 t->callback(epnum, t);
133 }
134 }
135}
136
137void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
138{
139 //LTRACE_ENTRY;
140
141 union usb_callback_args args;
142 args.setup = (struct usb_setup *)hpcd->Setup;
143
144 usbc_callback(USB_CB_SETUP_MSG, &args);
145}
146
147void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
148{
149 LTRACE_ENTRY;
150}
151
152void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
153{
154 LTRACE_ENTRY;
155
156 /* fail all the outstanding transactions */
157 for (uint i = 0; i < NUM_EP; i++) {
158 if (usbc.ep_in[i].transfer) {
159 usbc_transfer_t *t = usbc.ep_in[i].transfer;
160 usbc.ep_in[i].transfer = NULL;
161 t->result = ERR_CANCELLED;
162 t->callback(i, t);
163 }
164 if (usbc.ep_out[i].transfer) {
165 usbc_transfer_t *t = usbc.ep_out[i].transfer;
166 usbc.ep_out[i].transfer = NULL;
167 t->result = ERR_CANCELLED;
168 t->callback(i, t);
169 }
170 }
171
172 usbc_callback(USB_CB_RESET, NULL);
173}
174
175void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
176{
177 LTRACE_ENTRY;
178 usbc_callback(USB_CB_SUSPEND, NULL);
179}
180
181void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
182{
183 LTRACE_ENTRY;
184 usbc_callback(USB_CB_RESUME, NULL);
185}
186
187void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
188{
189 LTRACEF("epnum %u\n", epnum);
190}
191
192void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
193{
194 LTRACEF("epnum %u\n", epnum);
195}
196
197void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
198{
199 LTRACE_ENTRY;
200}
201
202void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
203{
204 LTRACE_ENTRY;
205}
206
207status_t usbc_set_active(bool active)
208{
209 LTRACEF("active %u\n", active);
210
211 if (active) {
212 HAL_PCD_Start(&usbc.handle);
213 } else {
214 HAL_PCD_Stop(&usbc.handle);
215 }
216
217 return NO_ERROR;
218}
219
220void usbc_set_address(uint8_t address)
221{
222 //LTRACEF("address %u\n", address);
223
224 HAL_PCD_SetAddress(&usbc.handle, address);
225}
226
227void usbc_ep0_ack(void)
228{
229 LTRACE;
230
231 HAL_PCD_EP_Transmit(&usbc.handle, 0, 0, 0);
232}
233
234void usbc_ep0_stall(void)
235{
236 LTRACE;
237
238 HAL_PCD_EP_SetStall(&usbc.handle, 0x80);
239}
240
241void usbc_ep0_send(const void *buf, size_t len, size_t maxlen)
242{
243 LTRACEF("buf %p, len %zu, maxlen %zu\n", buf, len, maxlen);
244
245 HAL_PCD_EP_Transmit(&usbc.handle, 0, (void *)buf, MIN(len, maxlen));
246}
247
248void usbc_ep0_recv(void *buf, size_t len, ep_callback cb)
249{
250 PANIC_UNIMPLEMENTED;
251}
252
253status_t usbc_setup_endpoint(ep_t ep, ep_dir_t dir, uint width)
254{
255 LTRACEF("ep %u dir %u width %u\n", ep, dir, width);
256
257 DEBUG_ASSERT(ep <= NUM_EP);
258
259 HAL_StatusTypeDef ret = HAL_PCD_EP_Open(&usbc.handle, ep | ((dir == USB_IN) ? 0x80 : 0), width, EP_TYPE_BULK);
260
261 // XXX be a little smarter here
262 if (dir == USB_IN) {
263 HAL_PCDEx_SetTxFiFo(&usbc.handle, ep, width);
264 }
265
266 return (ret == HAL_OK) ? NO_ERROR : ERR_GENERIC;
267}
268
269bool usbc_is_highspeed(void)
270{
271 return false;
272}
273
274status_t usbc_queue_rx(ep_t ep, usbc_transfer_t *transfer)
275{
276 LTRACEF("ep %u, transfer %p (buf %p, buflen %zu)\n", ep, transfer, transfer->buf, transfer->buflen);
277
278 DEBUG_ASSERT(ep <= NUM_EP);
279 DEBUG_ASSERT(usbc.ep_out[ep].transfer == NULL);
280
281 usbc.ep_out[ep].transfer = transfer;
282 HAL_PCD_EP_Receive(&usbc.handle, ep, transfer->buf, transfer->buflen);
283
284 return NO_ERROR;
285}
286
287status_t usbc_queue_tx(ep_t ep, usbc_transfer_t *transfer)
288{
289 LTRACEF("ep %u, transfer %p (buf %p, buflen %zu)\n", ep, transfer, transfer->buf, transfer->buflen);
290
291 DEBUG_ASSERT(ep <= NUM_EP);
292 DEBUG_ASSERT(usbc.ep_in[ep].transfer == NULL);
293
294 usbc.ep_in[ep].transfer = transfer;
295 HAL_PCD_EP_Transmit(&usbc.handle, ep, transfer->buf, transfer->buflen);
296
297 return NO_ERROR;
298}
299
300void stm32_OTG_FS_IRQ(void)
301{
302 arm_cm_irq_entry();
303 //LTRACE_ENTRY;
304
305 usbc.do_resched = false;
306 HAL_PCD_IRQHandler(&usbc.handle);
307
308 arm_cm_irq_exit(usbc.do_resched);
309}
310