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 <ddk/debug.h>
6 #include <hw/arch_ops.h>
7
8 #include "dwc3.h"
9 #include "dwc3-regs.h"
10
11 #include <stdio.h>
12 #include <unistd.h>
13
dwc3_handle_ep_event(dwc3_t * dwc,uint32_t event)14 static void dwc3_handle_ep_event(dwc3_t* dwc, uint32_t event) {
15 uint32_t type = DEPEVT_TYPE(event);
16 uint32_t ep_num = DEPEVT_PHYS_EP(event);
17 uint32_t status = DEPEVT_STATUS(event);
18
19 switch (type) {
20 case DEPEVT_XFER_COMPLETE:
21 dwc3_ep_xfer_complete(dwc, ep_num);
22 break;
23 case DEPEVT_XFER_IN_PROGRESS:
24 zxlogf(TRACE, "DEPEVT_XFER_IN_PROGRESS ep_num: %u status %u\n", ep_num, status);
25 break;
26 case DEPEVT_XFER_NOT_READY:
27 dwc3_ep_xfer_not_ready(dwc, ep_num, DEPEVT_XFER_NOT_READY_STAGE(event));
28 break;
29 case DEPEVT_STREAM_EVT:
30 zxlogf(TRACE, "DEPEVT_STREAM_EVT ep_num: %u status %u\n", ep_num, status);
31 break;
32 case DEPEVT_CMD_CMPLT: {
33 unsigned cmd_type = DEPEVT_CMD_CMPLT_CMD_TYPE(event);
34 unsigned rsrc_id = DEPEVT_CMD_CMPLT_RSRC_ID(event);
35 if (cmd_type == DEPCMD::DEPSTRTXFER) {
36 dwc3_ep_xfer_started(dwc, ep_num, rsrc_id);
37 }
38 break;
39 }
40 default:
41 zxlogf(ERROR, "dwc3_handle_ep_event: unknown event type %u\n", type);
42 break;
43 }
44 }
45
dwc3_handle_event(dwc3_t * dwc,uint32_t event)46 static void dwc3_handle_event(dwc3_t* dwc, uint32_t event) {
47 zxlogf(LTRACE, "dwc3_handle_event %08X\n", event);
48 if (!(event & DEPEVT_NON_EP)) {
49 dwc3_handle_ep_event(dwc, event);
50 return;
51 }
52
53 uint32_t type = DEVT_TYPE(event);
54 uint32_t info = DEVT_INFO(event);
55
56 switch (type) {
57 case DEVT_DISCONNECT:
58 zxlogf(TRACE, "DEVT_DISCONNECT\n");
59 break;
60 case DEVT_USB_RESET:
61 zxlogf(TRACE, "DEVT_USB_RESET\n");
62 dwc3_usb_reset(dwc);
63 break;
64 case DEVT_CONNECTION_DONE:
65 zxlogf(TRACE, "DEVT_CONNECTION_DONE\n");
66 dwc3_connection_done(dwc);
67 break;
68 case DEVT_LINK_STATE_CHANGE:
69 zxlogf(TRACE, "DEVT_LINK_STATE_CHANGE: ");
70 switch (info) {
71 case DSTS::USBLNKST_U0 | DEVT_LINK_STATE_CHANGE_SS:
72 zxlogf(TRACE, "DSTS::USBLNKST_U0\n");
73 break;
74 case DSTS::USBLNKST_U1 | DEVT_LINK_STATE_CHANGE_SS:
75 zxlogf(TRACE, "DSTS_USBLNKST_U1\n");
76 break;
77 case DSTS::USBLNKST_U2 | DEVT_LINK_STATE_CHANGE_SS:
78 zxlogf(TRACE, "DSTS_USBLNKST_U2\n");
79 break;
80 case DSTS::USBLNKST_U3 | DEVT_LINK_STATE_CHANGE_SS:
81 zxlogf(TRACE, "DSTS_USBLNKST_U3\n");
82 break;
83 case DSTS::USBLNKST_ESS_DIS | DEVT_LINK_STATE_CHANGE_SS:
84 zxlogf(TRACE, "DSTS_USBLNKST_ESS_DIS\n");
85 break;
86 case DSTS::USBLNKST_RX_DET | DEVT_LINK_STATE_CHANGE_SS:
87 zxlogf(TRACE, "DSTS_USBLNKST_RX_DET\n");
88 break;
89 case DSTS::USBLNKST_ESS_INACT | DEVT_LINK_STATE_CHANGE_SS:
90 zxlogf(TRACE, "DSTS_USBLNKST_ESS_INACT\n");
91 break;
92 case DSTS::USBLNKST_POLL | DEVT_LINK_STATE_CHANGE_SS:
93 zxlogf(TRACE, "DSTS_USBLNKST_POLL\n");
94 break;
95 case DSTS::USBLNKST_RECOV | DEVT_LINK_STATE_CHANGE_SS:
96 zxlogf(TRACE, "DSTS_USBLNKST_RECOV\n");
97 break;
98 case DSTS::USBLNKST_HRESET | DEVT_LINK_STATE_CHANGE_SS:
99 zxlogf(TRACE, "DSTS_USBLNKST_HRESET\n");
100 break;
101 case DSTS::USBLNKST_CMPLY | DEVT_LINK_STATE_CHANGE_SS:
102 zxlogf(TRACE, "DSTS_USBLNKST_CMPLY\n");
103 break;
104 case DSTS::USBLNKST_LPBK | DEVT_LINK_STATE_CHANGE_SS:
105 zxlogf(TRACE, "DSTS_USBLNKST_LPBK\n");
106 break;
107 case DSTS::USBLNKST_RESUME_RESET | DEVT_LINK_STATE_CHANGE_SS:
108 zxlogf(TRACE, "DSTS_USBLNKST_RESUME_RESET\n");
109 break;
110 case DSTS::USBLNKST_ON:
111 zxlogf(TRACE, "DSTS_USBLNKST_ON\n");
112 break;
113 case DSTS::USBLNKST_SLEEP:
114 zxlogf(TRACE, "DSTS_USBLNKST_SLEEP\n");
115 break;
116 case DSTS::USBLNKST_SUSPEND:
117 zxlogf(TRACE, "DSTS_USBLNKST_SUSPEND\n");
118 break;
119 case DSTS::USBLNKST_DISCONNECTED:
120 zxlogf(TRACE, "DSTS_USBLNKST_DISCONNECTED\n");
121 break;
122 case DSTS::USBLNKST_EARLY_SUSPEND:
123 zxlogf(TRACE, "DSTS_USBLNKST_EARLY_SUSPEND\n");
124 break;
125 case DSTS::USBLNKST_RESET:
126 zxlogf(TRACE, "DSTS_USBLNKST_RESET\n");
127 break;
128 case DSTS::USBLNKST_RESUME:
129 zxlogf(TRACE, "DSTS_USBLNKST_RESUME\n");
130 break;
131 default:
132 zxlogf(ERROR, "unknown state %d\n", info);
133 break;
134 }
135 break;
136 case DEVT_REMOTE_WAKEUP:
137 zxlogf(TRACE, "DEVT_REMOTE_WAKEUP\n");
138 break;
139 case DEVT_HIBERNATE_REQUEST:
140 zxlogf(TRACE, "DEVT_HIBERNATE_REQUEST\n");
141 break;
142 case DEVT_SUSPEND_ENTRY:
143 zxlogf(TRACE, "DEVT_SUSPEND_ENTRY\n");
144 //TODO(voydanoff) is this the best way to detect disconnect?
145 dwc3_disconnected(dwc);
146 break;
147 case DEVT_SOF:
148 zxlogf(TRACE, "DEVT_SOF\n");
149 break;
150 case DEVT_ERRATIC_ERROR:
151 zxlogf(TRACE, "DEVT_ERRATIC_ERROR\n");
152 break;
153 case DEVT_COMMAND_COMPLETE:
154 zxlogf(TRACE, "DEVT_COMMAND_COMPLETE\n");
155 break;
156 case DEVT_EVENT_BUF_OVERFLOW:
157 zxlogf(TRACE, "DEVT_EVENT_BUF_OVERFLOW\n");
158 break;
159 case DEVT_VENDOR_TEST_LMP:
160 zxlogf(TRACE, "DEVT_VENDOR_TEST_LMP\n");
161 break;
162 case DEVT_STOPPED_DISCONNECT:
163 zxlogf(TRACE, "DEVT_STOPPED_DISCONNECT\n");
164 break;
165 case DEVT_L1_RESUME_DETECT:
166 zxlogf(TRACE, "DEVT_L1_RESUME_DETECT\n");
167 break;
168 case DEVT_LDM_RESPONSE:
169 zxlogf(TRACE, "DEVT_LDM_RESPONSE\n");
170 break;
171 default:
172 zxlogf(ERROR, "dwc3_handle_event: unknown event type %u\n", type);
173 break;
174 }
175 }
176
dwc3_irq_thread(void * arg)177 static int dwc3_irq_thread(void* arg) {
178 auto* dwc = static_cast<dwc3_t*>(arg);
179 auto* mmio = dwc3_mmio(dwc);
180
181 zxlogf(TRACE, "dwc3_irq_thread start\n");
182
183 auto* ring_start = static_cast<uint32_t*>(io_buffer_virt(&dwc->event_buffer));
184 auto* ring_end = ring_start + EVENT_BUFFER_SIZE / sizeof(*ring_start);
185 auto* ring_cur = ring_start;
186
187 while (1) {
188 zx_status_t status = dwc->irq_handle.wait(nullptr);
189 if (status != ZX_OK) {
190 zxlogf(ERROR, "dwc3_irq_thread: zx_interrupt_wait returned %d\n", status);
191 break;
192 }
193 // read number of new bytes in the event buffer
194 uint32_t event_count;
195 while ((event_count = GEVNTCOUNT::Get(0).ReadFrom(mmio).EVNTCOUNT()) > 0) {
196 // invalidate cache so we can read fresh events
197 io_buffer_cache_flush_invalidate(&dwc->event_buffer, 0, EVENT_BUFFER_SIZE);
198
199 for (uint32_t i = 0; i < event_count; i += static_cast<uint32_t>(sizeof(uint32_t))) {
200 uint32_t event = *ring_cur++;
201 if (ring_cur == ring_end) {
202 ring_cur = ring_start;
203 }
204 dwc3_handle_event(dwc, event);
205 }
206
207 // acknowledge the events we have processed
208 GEVNTCOUNT::Get(0).FromValue(0).set_EVNTCOUNT(event_count).WriteTo(mmio);
209 }
210 }
211
212 zxlogf(TRACE, "dwc3_irq_thread done\n");
213 return 0;
214 }
215
dwc3_events_start(dwc3_t * dwc)216 void dwc3_events_start(dwc3_t* dwc) {
217 auto* mmio = dwc3_mmio(dwc);
218
219 // set event buffer pointer and size
220 // keep interrupts masked until we are ready
221 zx_paddr_t paddr = io_buffer_phys(&dwc->event_buffer);
222 GEVNTADR::Get(0).FromValue(0).set_EVNTADR(paddr).WriteTo(mmio);
223 GEVNTSIZ::Get(0).FromValue(0).set_EVENTSIZ(EVENT_BUFFER_SIZE).set_EVNTINTRPTMASK(1)
224 .WriteTo(mmio);
225 GEVNTCOUNT::Get(0).FromValue(0).set_EVNTCOUNT(0).WriteTo(mmio);
226
227 // enable events
228 DEVTEN::Get()
229 .FromValue(0)
230 .set_L1SUSPEN(1)
231 .set_U3L2L1SuspEn(1)
232 .set_CONNECTDONEEVTEN(1)
233 .set_USBRSTEVTEN(1)
234 .set_DISSCONNEVTEN(1)
235 .WriteTo(mmio);
236
237 thrd_create_with_name(&dwc->irq_thread, dwc3_irq_thread, dwc, "dwc3_irq_thread");
238 }
239
dwc3_events_stop(dwc3_t * dwc)240 void dwc3_events_stop(dwc3_t* dwc) {
241 dwc->irq_handle.destroy();
242 thrd_join(dwc->irq_thread, nullptr);
243 }
244