1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <assert.h>
6#include <ddk/debug.h>
7#include <zircon/assert.h>
8
9#include <ddk/usb-request/usb-request.h>
10
11#include "dwc3.h"
12#include "dwc3-regs.h"
13#include "dwc3-types.h"
14
15#include <stdio.h>
16#include <string.h>
17
18#define EP_FIFO_SIZE    PAGE_SIZE
19
20static zx_paddr_t dwc3_ep_trb_phys(dwc3_endpoint_t* ep, dwc3_trb_t* trb) {
21    return io_buffer_phys(&ep->fifo.buffer) + ((void *)trb - (void *)ep->fifo.first);
22}
23
24static void dwc3_enable_ep(dwc3_t* dwc, unsigned ep_num, bool enable) {
25    volatile void* reg = dwc3_mmio(dwc) + DALEPENA;
26
27    mtx_lock(&dwc->lock);
28
29    uint32_t temp = DWC3_READ32(reg);
30    uint32_t bit = 1 << ep_num;
31
32    if (enable) {
33        temp |= bit;
34    } else {
35        temp &= ~bit;
36    }
37    DWC3_WRITE32(reg, temp);
38
39    mtx_unlock(&dwc->lock);
40}
41
42zx_status_t dwc3_ep_fifo_init(dwc3_t* dwc, unsigned ep_num) {
43    ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps));
44    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
45    dwc3_fifo_t* fifo = &ep->fifo;
46
47    static_assert(EP_FIFO_SIZE <= PAGE_SIZE, "");
48    zx_status_t status = io_buffer_init(&fifo->buffer, dwc->bti_handle, EP_FIFO_SIZE,
49                                        IO_BUFFER_RW | IO_BUFFER_CONTIG);
50    if (status != ZX_OK) {
51        return status;
52    }
53
54    fifo->first = io_buffer_virt(&fifo->buffer);
55    fifo->next = fifo->first;
56    fifo->current = NULL;
57    fifo->last = (void *)fifo->first + EP_FIFO_SIZE - sizeof(dwc3_trb_t);
58
59    // set up link TRB pointing back to the start of the fifo
60    dwc3_trb_t* trb = fifo->last;
61    zx_paddr_t trb_phys = io_buffer_phys(&fifo->buffer);
62    trb->ptr_low = (uint32_t)trb_phys;
63    trb->ptr_high = (uint32_t)(trb_phys >> 32);
64    trb->status = 0;
65    trb->control = TRB_TRBCTL_LINK | TRB_HWO;
66    io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
67
68    return ZX_OK;
69}
70
71void dwc3_ep_fifo_release(dwc3_t* dwc, unsigned ep_num) {
72    ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps));
73    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
74
75    io_buffer_release(&ep->fifo.buffer);
76}
77
78void dwc3_ep_start_transfer(dwc3_t* dwc, unsigned ep_num, unsigned type, zx_paddr_t buffer,
79                            size_t length, bool send_zlp) {
80    zxlogf(LTRACE, "dwc3_ep_start_transfer ep %u type %u length %zu\n", ep_num, type, length);
81
82    // special case: EP0_OUT and EP0_IN use the same fifo
83    dwc3_endpoint_t* ep = (ep_num == EP0_IN ? &dwc->eps[EP0_OUT] : &dwc->eps[ep_num]);
84
85    dwc3_trb_t* trb = ep->fifo.next++;
86    if (ep->fifo.next == ep->fifo.last) {
87        ep->fifo.next = ep->fifo.first;
88    }
89    if (ep->fifo.current == NULL) {
90        ep->fifo.current = trb;
91    }
92
93    trb->ptr_low = (uint32_t)buffer;
94    trb->ptr_high = (uint32_t)(buffer >> 32);
95    trb->status = TRB_BUFSIZ(length);
96    if (send_zlp) {
97        trb->control = type | TRB_HWO;
98    } else {
99        trb->control = type | TRB_LST | TRB_IOC | TRB_HWO;
100    }
101    io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
102
103    if (send_zlp) {
104        dwc3_trb_t* zlp_trb = ep->fifo.next++;
105        if (ep->fifo.next == ep->fifo.last) {
106            ep->fifo.next = ep->fifo.first;
107        }
108        zlp_trb->ptr_low = 0;
109        zlp_trb->ptr_high = 0;
110        zlp_trb->status = TRB_BUFSIZ(0);
111        zlp_trb->control = type | TRB_LST | TRB_IOC | TRB_HWO;
112        io_buffer_cache_flush(&ep->fifo.buffer, (zlp_trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
113    }
114
115    dwc3_cmd_ep_start_transfer(dwc, ep_num, dwc3_ep_trb_phys(ep, trb));
116}
117
118static void dwc3_ep_queue_next_locked(dwc3_t* dwc, dwc3_endpoint_t* ep) {
119    usb_request_t* req;
120
121    if (ep->current_req == NULL && ep->got_not_ready &&
122        (req = list_remove_head_type(&ep->queued_reqs, usb_request_t, node)) != NULL) {
123        ep->current_req = req;
124        ep->got_not_ready = false;
125        if (EP_IN(ep->ep_num)) {
126            usb_request_cache_flush(req, 0, req->header.length);
127        } else {
128            usb_request_cache_flush_invalidate(req, 0, req->header.length);
129        }
130
131        // TODO(voydanoff) scatter/gather support
132        phys_iter_t iter;
133        zx_paddr_t phys;
134        usb_request_physmap(req, dwc->bti_handle);
135        usb_request_phys_iter_init(&iter, req, PAGE_SIZE);
136        usb_request_phys_iter_next(&iter, &phys);
137        bool send_zlp = req->header.send_zlp && (req->header.length % ep->max_packet_size) == 0;
138        dwc3_ep_start_transfer(dwc, ep->ep_num, TRB_TRBCTL_NORMAL, phys, req->header.length,
139                               send_zlp);
140    }
141}
142
143zx_status_t dwc3_ep_config(dwc3_t* dwc, usb_endpoint_descriptor_t* ep_desc,
144                                  usb_ss_ep_comp_descriptor_t* ss_comp_desc) {
145    // convert address to index in range 0 - 31
146    // low bit is IN/OUT
147    unsigned ep_num = dwc3_ep_num(ep_desc->bEndpointAddress);
148    if (ep_num < 2) {
149        // index 0 and 1 are for endpoint zero
150        return ZX_ERR_INVALID_ARGS;
151    }
152
153    unsigned ep_type = usb_ep_type(ep_desc);
154    if (ep_type == USB_ENDPOINT_ISOCHRONOUS) {
155        zxlogf(ERROR, "dwc3_ep_config: isochronous endpoints are not supported\n");
156        return ZX_ERR_NOT_SUPPORTED;
157    }
158
159    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
160
161    mtx_lock(&ep->lock);
162    zx_status_t status = dwc3_ep_fifo_init(dwc, ep_num);
163    if (status != ZX_OK) {
164        zxlogf(ERROR, "dwc3_config_ep: dwc3_ep_fifo_init failed %d\n", status);
165        mtx_unlock(&ep->lock);
166        return status;
167    }
168    ep->max_packet_size = usb_ep_max_packet(ep_desc);
169    ep->type = ep_type;
170    ep->interval = ep_desc->bInterval;
171    // TODO(voydanoff) USB3 support
172
173    ep->enabled = true;
174
175    if (dwc->configured) {
176        dwc3_ep_queue_next_locked(dwc, ep);
177    }
178
179    mtx_unlock(&ep->lock);
180
181    return ZX_OK;
182}
183
184zx_status_t dwc3_ep_disable(dwc3_t* dwc, uint8_t ep_addr) {
185    // convert address to index in range 0 - 31
186    // low bit is IN/OUT
187    unsigned ep_num = dwc3_ep_num(ep_addr);
188    if (ep_num < 2) {
189        // index 0 and 1 are for endpoint zero
190        return ZX_ERR_INVALID_ARGS;
191    }
192
193    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
194    mtx_lock(&ep->lock);
195    dwc3_ep_fifo_release(dwc, ep_num);
196    ep->enabled = false;
197    mtx_unlock(&ep->lock);
198
199    return ZX_OK;
200}
201
202void dwc3_ep_queue(dwc3_t* dwc, unsigned ep_num, usb_request_t* req) {
203    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
204
205    // OUT transactions must have length > 0 and multiple of max packet size
206    if (EP_OUT(ep_num)) {
207        if (req->header.length == 0 || req->header.length % ep->max_packet_size != 0) {
208            zxlogf(ERROR, "dwc3_ep_queue: OUT transfers must be multiple of max packet size\n");
209            usb_request_complete(req, ZX_ERR_INVALID_ARGS, 0);
210            return;
211        }
212    }
213
214    mtx_lock(&ep->lock);
215
216    if (!ep->enabled) {
217        mtx_unlock(&ep->lock);
218        usb_request_complete(req, ZX_ERR_BAD_STATE, 0);
219        return;
220    }
221
222    list_add_tail(&ep->queued_reqs, &req->node);
223
224    if (dwc->configured) {
225        dwc3_ep_queue_next_locked(dwc, ep);
226    }
227
228    mtx_unlock(&ep->lock);
229}
230
231void dwc3_ep_set_config(dwc3_t* dwc, unsigned ep_num, bool enable) {
232    zxlogf(TRACE, "dwc3_ep_set_config %u\n", ep_num);
233
234    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
235
236    if (enable) {
237        dwc3_cmd_ep_set_config(dwc, ep_num, ep->type, ep->max_packet_size, ep->interval, false);
238        dwc3_cmd_ep_transfer_config(dwc, ep_num);
239        dwc3_enable_ep(dwc, ep_num, true);
240    } else {
241        dwc3_enable_ep(dwc, ep_num, false);
242    }
243}
244
245void dwc3_start_eps(dwc3_t* dwc) {
246    zxlogf(TRACE, "dwc3_start_eps\n");
247
248    dwc3_cmd_ep_set_config(dwc, EP0_IN, USB_ENDPOINT_CONTROL, dwc->eps[EP0_IN].max_packet_size, 0,
249                           true);
250    dwc3_cmd_start_new_config(dwc, EP0_OUT, 2);
251
252    for (unsigned ep_num = 2; ep_num < countof(dwc->eps); ep_num++) {
253        dwc3_endpoint_t* ep = &dwc->eps[ep_num];
254        if (ep->enabled) {
255            dwc3_ep_set_config(dwc, ep_num, true);
256
257            mtx_lock(&ep->lock);
258            dwc3_ep_queue_next_locked(dwc, ep);
259            mtx_unlock(&ep->lock);
260        }
261    }
262}
263
264static void dwc_ep_read_trb(dwc3_endpoint_t* ep, dwc3_trb_t* trb, dwc3_trb_t* out_trb) {
265    if (trb >= ep->fifo.first && trb < ep->fifo.last) {
266        io_buffer_cache_flush_invalidate(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb),
267                                         sizeof(*trb));
268        memcpy((void *)out_trb, (void *)trb, sizeof(*trb));
269    } else {
270        zxlogf(ERROR, "dwc_ep_read_trb: bad trb\n");
271    }
272}
273
274void dwc3_ep_xfer_started(dwc3_t* dwc, unsigned ep_num, unsigned rsrc_id) {
275    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
276    mtx_lock(&ep->lock);
277    ep->rsrc_id = rsrc_id;
278    mtx_unlock(&ep->lock);
279}
280
281void dwc3_ep_xfer_not_ready(dwc3_t* dwc, unsigned ep_num, unsigned stage) {
282    zxlogf(LTRACE, "dwc3_ep_xfer_not_ready ep %u state %d\n", ep_num, dwc->ep0_state);
283
284    if (ep_num == EP0_OUT || ep_num == EP0_IN) {
285        dwc3_ep0_xfer_not_ready(dwc, ep_num, stage);
286    } else {
287        dwc3_endpoint_t* ep = &dwc->eps[ep_num];
288
289        mtx_lock(&ep->lock);
290        ep->got_not_ready = true;
291        dwc3_ep_queue_next_locked(dwc, ep);
292        mtx_unlock(&ep->lock);
293    }
294}
295
296void dwc3_ep_xfer_complete(dwc3_t* dwc, unsigned ep_num) {
297    zxlogf(LTRACE, "dwc3_ep_xfer_complete ep %u state %d\n", ep_num, dwc->ep0_state);
298
299    if (ep_num >= countof(dwc->eps)) {
300        zxlogf(ERROR, "dwc3_ep_xfer_complete: bad ep_num %u\n", ep_num);
301        return;
302    }
303
304    if (ep_num == EP0_OUT || ep_num == EP0_IN) {
305        dwc3_ep0_xfer_complete(dwc, ep_num);
306    } else {
307        dwc3_endpoint_t* ep = &dwc->eps[ep_num];
308
309        mtx_lock(&ep->lock);
310        usb_request_t* req = ep->current_req;
311        ep->current_req = NULL;
312
313        if (req) {
314            dwc3_trb_t  trb;
315            dwc_ep_read_trb(ep, ep->fifo.current, &trb);
316            ep->fifo.current = NULL;
317            if (trb.control & TRB_HWO) {
318                zxlogf(ERROR, "TRB_HWO still set in dwc3_ep_xfer_complete\n");
319            }
320
321            zx_off_t actual = req->header.length - TRB_BUFSIZ(trb.status);
322//            dwc3_ep_queue_next_locked(dwc, ep);
323
324            mtx_unlock(&ep->lock);
325
326            usb_request_complete(req, ZX_OK, actual);
327        } else {
328            mtx_unlock(&ep->lock);
329            zxlogf(ERROR, "dwc3_ep_xfer_complete: no usb request found to complete!\n");
330        }
331    }
332}
333
334zx_status_t dwc3_ep_set_stall(dwc3_t* dwc, unsigned ep_num, bool stall) {
335    if (ep_num >= countof(dwc->eps)) {
336        return ZX_ERR_INVALID_ARGS;
337    }
338
339    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
340    mtx_lock(&ep->lock);
341
342    if (!ep->enabled) {
343        mtx_unlock(&ep->lock);
344        return ZX_ERR_BAD_STATE;
345    }
346    if (stall && !ep->stalled) {
347        dwc3_cmd_ep_set_stall(dwc, ep_num);
348    } else if (!stall && ep->stalled) {
349        dwc3_cmd_ep_clear_stall(dwc, ep_num);
350    }
351    ep->stalled = stall;
352    mtx_unlock(&ep->lock);
353
354    return ZX_OK;
355}
356
357void dwc3_ep_end_transfers(dwc3_t* dwc, unsigned ep_num, zx_status_t reason) {
358    dwc3_endpoint_t* ep = &dwc->eps[ep_num];
359    mtx_lock(&ep->lock);
360
361    if (ep->current_req) {
362        dwc3_cmd_ep_end_transfer(dwc, ep_num);
363        usb_request_complete(ep->current_req, reason, 0);
364        ep->current_req = NULL;
365    }
366
367    usb_request_t* req;
368    while ((req = list_remove_head_type(&ep->queued_reqs, usb_request_t, node)) != NULL) {
369        usb_request_complete(req, reason, 0);
370    }
371
372    mtx_unlock(&ep->lock);
373}
374