Branch data Line data Source code
1 : :
2 : : /* ==========================================================================
3 : : * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
4 : : * $Revision: #104 $
5 : : * $Date: 2011/10/24 $
6 : : * $Change: 1871159 $
7 : : *
8 : : * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
9 : : * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
10 : : * otherwise expressly agreed to in writing between Synopsys and you.
11 : : *
12 : : * The Software IS NOT an item of Licensed Software or Licensed Product under
13 : : * any End User Software License Agreement or Agreement for Licensed Product
14 : : * with Synopsys or any supplement thereto. You are permitted to use and
15 : : * redistribute this Software in source and binary forms, with or without
16 : : * modification, provided that redistributions of source code must retain this
17 : : * notice. You may not view, use, disclose, copy or distribute this file or
18 : : * any information contained herein except pursuant to this license grant from
19 : : * Synopsys. If you do not agree with this notice, including the disclaimer
20 : : * below, then you are not authorized to use the Software.
21 : : *
22 : : * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
23 : : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 : : * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
26 : : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 : : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 : : * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32 : : * DAMAGE.
33 : : * ========================================================================== */
34 : : #ifndef DWC_DEVICE_ONLY
35 : :
36 : : /** @file
37 : : * This file implements HCD Core. All code in this file is portable and doesn't
38 : : * use any OS specific functions.
39 : : * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
40 : : * header file.
41 : : */
42 : :
43 : : #include <linux/usb.h>
44 : : #include <linux/usb/hcd.h>
45 : :
46 : : #include "dwc_otg_hcd.h"
47 : : #include "dwc_otg_regs.h"
48 : : #include "dwc_otg_fiq_fsm.h"
49 : :
50 : : extern bool microframe_schedule;
51 : : extern uint16_t fiq_fsm_mask, nak_holdoff;
52 : :
53 : : //#define DEBUG_HOST_CHANNELS
54 : : #ifdef DEBUG_HOST_CHANNELS
55 : : static int last_sel_trans_num_per_scheduled = 0;
56 : : static int last_sel_trans_num_nonper_scheduled = 0;
57 : : static int last_sel_trans_num_avail_hc_at_start = 0;
58 : : static int last_sel_trans_num_avail_hc_at_end = 0;
59 : : #endif /* DEBUG_HOST_CHANNELS */
60 : :
61 : :
62 : 404 : dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
63 : : {
64 : 404 : return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
65 : : }
66 : :
67 : : /**
68 : : * Connection timeout function. An OTG host is required to display a
69 : : * message if the device does not connect within 10 seconds.
70 : : */
71 : 0 : void dwc_otg_hcd_connect_timeout(void *ptr)
72 : : {
73 : : DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
74 : 0 : DWC_PRINTF("Connect Timeout\n");
75 : 0 : __DWC_ERROR("Device Not Connected/Responding\n");
76 : 0 : }
77 : :
78 : : #if defined(DEBUG)
79 : : static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
80 : : {
81 : : if (qh->channel != NULL) {
82 : : dwc_hc_t *hc = qh->channel;
83 : : dwc_list_link_t *item;
84 : : dwc_otg_qh_t *qh_item;
85 : : int num_channels = hcd->core_if->core_params->host_channels;
86 : : int i;
87 : :
88 : : dwc_otg_hc_regs_t *hc_regs;
89 : : hcchar_data_t hcchar;
90 : : hcsplt_data_t hcsplt;
91 : : hctsiz_data_t hctsiz;
92 : : uint32_t hcdma;
93 : :
94 : : hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
95 : : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
96 : : hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
97 : : hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
98 : : hcdma = DWC_READ_REG32(&hc_regs->hcdma);
99 : :
100 : : DWC_PRINTF(" Assigned to channel %p:\n", hc);
101 : : DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
102 : : hcsplt.d32);
103 : : DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
104 : : hcdma);
105 : : DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
106 : : hc->dev_addr, hc->ep_num, hc->ep_is_in);
107 : : DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
108 : : DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
109 : : DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
110 : : DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
111 : : DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
112 : : DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
113 : : DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
114 : : DWC_PRINTF(" qh: %p\n", hc->qh);
115 : : DWC_PRINTF(" NP inactive sched:\n");
116 : : DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
117 : : qh_item =
118 : : DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
119 : : DWC_PRINTF(" %p\n", qh_item);
120 : : }
121 : : DWC_PRINTF(" NP active sched:\n");
122 : : DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
123 : : qh_item =
124 : : DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
125 : : DWC_PRINTF(" %p\n", qh_item);
126 : : }
127 : : DWC_PRINTF(" Channels: \n");
128 : : for (i = 0; i < num_channels; i++) {
129 : : dwc_hc_t *hc = hcd->hc_ptr_array[i];
130 : : DWC_PRINTF(" %2d: %p\n", i, hc);
131 : : }
132 : : }
133 : : }
134 : : #else
135 : : #define dump_channel_info(hcd, qh)
136 : : #endif /* DEBUG */
137 : :
138 : : /**
139 : : * Work queue function for starting the HCD when A-Cable is connected.
140 : : * The hcd_start() must be called in a process context.
141 : : */
142 : 0 : static void hcd_start_func(void *_vp)
143 : : {
144 : : dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
145 : :
146 : : DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
147 [ # # ]: 0 : if (hcd) {
148 : 0 : hcd->fops->start(hcd);
149 : : }
150 : 0 : }
151 : :
152 : : static void del_xfer_timers(dwc_otg_hcd_t * hcd)
153 : : {
154 : : #ifdef DEBUG
155 : : int i;
156 : : int num_channels = hcd->core_if->core_params->host_channels;
157 : : for (i = 0; i < num_channels; i++) {
158 : : DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
159 : : }
160 : : #endif
161 : : }
162 : :
163 : : static void del_timers(dwc_otg_hcd_t * hcd)
164 : : {
165 : : del_xfer_timers(hcd);
166 : 0 : DWC_TIMER_CANCEL(hcd->conn_timer);
167 : : }
168 : :
169 : : /**
170 : : * Processes all the URBs in a single list of QHs. Completes them with
171 : : * -ESHUTDOWN and frees the QTD.
172 : : */
173 : 0 : static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
174 : : {
175 : : dwc_list_link_t *qh_item, *qh_tmp;
176 : : dwc_otg_qh_t *qh;
177 : : dwc_otg_qtd_t *qtd, *qtd_tmp;
178 : : int quiesced = 0;
179 : :
180 [ # # ]: 0 : DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
181 : 0 : qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
182 [ # # ]: 0 : DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
183 : : &qh->qtd_list, qtd_list_entry) {
184 : 0 : qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
185 [ # # ]: 0 : if (qtd->urb != NULL) {
186 : 0 : hcd->fops->complete(hcd, qtd->urb->priv,
187 : : qtd->urb, -DWC_E_SHUTDOWN);
188 : 0 : dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
189 : : }
190 : :
191 : : }
192 [ # # ]: 0 : if(qh->channel) {
193 : 0 : int n = qh->channel->hc_num;
194 : : /* Using hcchar.chen == 1 is not a reliable test.
195 : : * It is possible that the channel has already halted
196 : : * but not yet been through the IRQ handler.
197 : : */
198 [ # # # # ]: 0 : if (fiq_fsm_enable && (hcd->fiq_state->channel[qh->channel->hc_num].fsm != FIQ_PASSTHROUGH)) {
199 : 0 : qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
200 : 0 : qh->channel->halt_pending = 1;
201 [ # # ]: 0 : if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
202 : : hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
203 : 0 : hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
204 : : /* We're called from disconnect callback or in the middle of freeing the HCD here,
205 : : * so FIQ is disabled, top-level interrupts masked and we're holding the spinlock.
206 : : * No further URBs will be submitted, but wait 1 microframe for any previously
207 : : * submitted periodic DMA to finish.
208 : : */
209 [ # # ]: 0 : if (!quiesced) {
210 : 0 : udelay(125);
211 : : quiesced = 1;
212 : : }
213 : : } else {
214 : 0 : dwc_otg_hc_halt(hcd->core_if, qh->channel,
215 : : DWC_OTG_HC_XFER_URB_DEQUEUE);
216 : : }
217 : 0 : qh->channel = NULL;
218 : : }
219 : 0 : dwc_otg_hcd_qh_remove(hcd, qh);
220 : : }
221 : 0 : }
222 : :
223 : : /**
224 : : * Responds with an error status of ESHUTDOWN to all URBs in the non-periodic
225 : : * and periodic schedules. The QTD associated with each URB is removed from
226 : : * the schedule and freed. This function may be called when a disconnect is
227 : : * detected or when the HCD is being stopped.
228 : : */
229 : 0 : static void kill_all_urbs(dwc_otg_hcd_t * hcd)
230 : : {
231 : 0 : kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
232 : 0 : kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
233 : 0 : kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
234 : 0 : kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
235 : 0 : kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
236 : 0 : kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
237 : 0 : }
238 : :
239 : : /**
240 : : * Start the connection timer. An OTG host is required to display a
241 : : * message if the device does not connect within 10 seconds. The
242 : : * timer is deleted if a port connect interrupt occurs before the
243 : : * timer expires.
244 : : */
245 : : static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
246 : : {
247 : 0 : DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
248 : : }
249 : :
250 : : /**
251 : : * HCD Callback function for disconnect of the HCD.
252 : : *
253 : : * @param p void pointer to the <code>struct usb_hcd</code>
254 : : */
255 : 0 : static int32_t dwc_otg_hcd_session_start_cb(void *p)
256 : : {
257 : : dwc_otg_hcd_t *dwc_otg_hcd;
258 : : DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
259 : : dwc_otg_hcd = p;
260 : : dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
261 : 0 : return 1;
262 : : }
263 : :
264 : : /**
265 : : * HCD Callback function for starting the HCD when A-Cable is
266 : : * connected.
267 : : *
268 : : * @param p void pointer to the <code>struct usb_hcd</code>
269 : : */
270 : 0 : static int32_t dwc_otg_hcd_start_cb(void *p)
271 : : {
272 : : dwc_otg_hcd_t *dwc_otg_hcd = p;
273 : : dwc_otg_core_if_t *core_if;
274 : : hprt0_data_t hprt0;
275 : :
276 : 0 : core_if = dwc_otg_hcd->core_if;
277 : :
278 [ # # ]: 0 : if (core_if->op_state == B_HOST) {
279 : : /*
280 : : * Reset the port. During a HNP mode switch the reset
281 : : * needs to occur within 1ms and have a duration of at
282 : : * least 50ms.
283 : : */
284 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
285 : 0 : hprt0.b.prtrst = 1;
286 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
287 : : }
288 : 0 : DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
289 : : hcd_start_func, dwc_otg_hcd, 50,
290 : : "start hcd");
291 : :
292 : 0 : return 1;
293 : : }
294 : :
295 : : /**
296 : : * HCD Callback function for disconnect of the HCD.
297 : : *
298 : : * @param p void pointer to the <code>struct usb_hcd</code>
299 : : */
300 : 0 : static int32_t dwc_otg_hcd_disconnect_cb(void *p)
301 : : {
302 : : gintsts_data_t intr;
303 : : dwc_otg_hcd_t *dwc_otg_hcd = p;
304 : :
305 : 0 : DWC_SPINLOCK(dwc_otg_hcd->lock);
306 : : /*
307 : : * Set status flags for the hub driver.
308 : : */
309 : 0 : dwc_otg_hcd->flags.b.port_connect_status_change = 1;
310 : 0 : dwc_otg_hcd->flags.b.port_connect_status = 0;
311 [ # # ]: 0 : if(fiq_enable) {
312 : 0 : local_fiq_disable();
313 : 0 : fiq_fsm_spin_lock(&dwc_otg_hcd->fiq_state->lock);
314 : : }
315 : : /*
316 : : * Shutdown any transfers in process by clearing the Tx FIFO Empty
317 : : * interrupt mask and status bits and disabling subsequent host
318 : : * channel interrupts.
319 : : */
320 : 0 : intr.d32 = 0;
321 : 0 : intr.b.nptxfempty = 1;
322 : 0 : intr.b.ptxfempty = 1;
323 : 0 : intr.b.hcintr = 1;
324 : 0 : DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
325 : : intr.d32, 0);
326 : 0 : DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
327 : : intr.d32, 0);
328 : :
329 : : del_timers(dwc_otg_hcd);
330 : :
331 : : /*
332 : : * Turn off the vbus power only if the core has transitioned to device
333 : : * mode. If still in host mode, need to keep power on to detect a
334 : : * reconnection.
335 : : */
336 [ # # ]: 0 : if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
337 [ # # ]: 0 : if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
338 : 0 : hprt0_data_t hprt0 = {.d32 = 0 };
339 : 0 : DWC_PRINTF("Disconnect: PortPower off\n");
340 : 0 : hprt0.b.prtpwr = 0;
341 : 0 : DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
342 : : hprt0.d32);
343 : : }
344 : :
345 : 0 : dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
346 : : }
347 : :
348 : : /* Respond with an error status to all URBs in the schedule. */
349 : 0 : kill_all_urbs(dwc_otg_hcd);
350 : :
351 [ # # ]: 0 : if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
352 : : /* Clean up any host channels that were in use. */
353 : : int num_channels;
354 : : int i;
355 : : dwc_hc_t *channel;
356 : : dwc_otg_hc_regs_t *hc_regs;
357 : : hcchar_data_t hcchar;
358 : :
359 : 0 : num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
360 : :
361 [ # # ]: 0 : if (!dwc_otg_hcd->core_if->dma_enable) {
362 : : /* Flush out any channel requests in slave mode. */
363 [ # # ]: 0 : for (i = 0; i < num_channels; i++) {
364 : 0 : channel = dwc_otg_hcd->hc_ptr_array[i];
365 [ # # # # ]: 0 : if (DWC_CIRCLEQ_EMPTY_ENTRY
366 : : (channel, hc_list_entry)) {
367 : 0 : hc_regs =
368 : 0 : dwc_otg_hcd->core_if->
369 : : host_if->hc_regs[i];
370 : 0 : hcchar.d32 =
371 : 0 : DWC_READ_REG32(&hc_regs->hcchar);
372 [ # # ]: 0 : if (hcchar.b.chen) {
373 : 0 : hcchar.b.chen = 0;
374 : 0 : hcchar.b.chdis = 1;
375 : 0 : hcchar.b.epdir = 0;
376 : 0 : DWC_WRITE_REG32
377 : : (&hc_regs->hcchar,
378 : : hcchar.d32);
379 : : }
380 : : }
381 : : }
382 : : }
383 : :
384 [ # # ]: 0 : if(fiq_fsm_enable) {
385 [ # # ]: 0 : for(i=0; i < 128; i++) {
386 : 0 : dwc_otg_hcd->hub_port[i] = 0;
387 : : }
388 : : }
389 : : }
390 : :
391 [ # # ]: 0 : if(fiq_enable) {
392 : 0 : fiq_fsm_spin_unlock(&dwc_otg_hcd->fiq_state->lock);
393 : 0 : local_fiq_enable();
394 : : }
395 : :
396 [ # # ]: 0 : if (dwc_otg_hcd->fops->disconnect) {
397 : 0 : dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
398 : : }
399 : :
400 : 0 : DWC_SPINUNLOCK(dwc_otg_hcd->lock);
401 : 0 : return 1;
402 : : }
403 : :
404 : : /**
405 : : * HCD Callback function for stopping the HCD.
406 : : *
407 : : * @param p void pointer to the <code>struct usb_hcd</code>
408 : : */
409 : 0 : static int32_t dwc_otg_hcd_stop_cb(void *p)
410 : : {
411 : : dwc_otg_hcd_t *dwc_otg_hcd = p;
412 : :
413 : : DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
414 : 0 : dwc_otg_hcd_stop(dwc_otg_hcd);
415 : 0 : return 1;
416 : : }
417 : :
418 : : #ifdef CONFIG_USB_DWC_OTG_LPM
419 : : /**
420 : : * HCD Callback function for sleep of HCD.
421 : : *
422 : : * @param p void pointer to the <code>struct usb_hcd</code>
423 : : */
424 : : static int dwc_otg_hcd_sleep_cb(void *p)
425 : : {
426 : : dwc_otg_hcd_t *hcd = p;
427 : :
428 : : dwc_otg_hcd_free_hc_from_lpm(hcd);
429 : :
430 : : return 0;
431 : : }
432 : : #endif
433 : :
434 : :
435 : : /**
436 : : * HCD Callback function for Remote Wakeup.
437 : : *
438 : : * @param p void pointer to the <code>struct usb_hcd</code>
439 : : */
440 : 0 : static int dwc_otg_hcd_rem_wakeup_cb(void *p)
441 : : {
442 : : dwc_otg_hcd_t *hcd = p;
443 : :
444 [ # # ]: 0 : if (hcd->core_if->lx_state == DWC_OTG_L2) {
445 : 0 : hcd->flags.b.port_suspend_change = 1;
446 : : }
447 : : #ifdef CONFIG_USB_DWC_OTG_LPM
448 : : else {
449 : : hcd->flags.b.port_l1_change = 1;
450 : : }
451 : : #endif
452 : 0 : return 0;
453 : : }
454 : :
455 : : /**
456 : : * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
457 : : * stopped.
458 : : */
459 : 0 : void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
460 : : {
461 : 0 : hprt0_data_t hprt0 = {.d32 = 0 };
462 : :
463 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
464 : :
465 : : /*
466 : : * The root hub should be disconnected before this function is called.
467 : : * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
468 : : * and the QH lists (via ..._hcd_endpoint_disable).
469 : : */
470 : :
471 : : /* Turn off all host-specific interrupts. */
472 : 0 : dwc_otg_disable_host_interrupts(hcd->core_if);
473 : :
474 : : /* Turn off the vbus power */
475 : 0 : DWC_PRINTF("PortPower off\n");
476 : 0 : hprt0.b.prtpwr = 0;
477 : 0 : DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
478 : 0 : dwc_mdelay(1);
479 : 0 : }
480 : :
481 : 185636 : int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
482 : : dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
483 : : int atomic_alloc)
484 : : {
485 : : int retval = 0;
486 : : uint8_t needs_scheduling = 0;
487 : : dwc_otg_transaction_type_e tr_type;
488 : : dwc_otg_qtd_t *qtd;
489 : : gintmsk_data_t intr_mask = {.d32 = 0 };
490 : : hprt0_data_t hprt0 = { .d32 = 0 };
491 : :
492 : : #ifdef DEBUG /* integrity checks (Broadcom) */
493 : : if (NULL == hcd->core_if) {
494 : : DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
495 : : /* No longer connected. */
496 : : return -DWC_E_INVALID;
497 : : }
498 : : #endif
499 [ - + ]: 185636 : if (!hcd->flags.b.port_connect_status) {
500 : : /* No longer connected. */
501 : 0 : DWC_ERROR("Not connected\n");
502 : 0 : return -DWC_E_NO_DEVICE;
503 : : }
504 : :
505 : : /* Some core configurations cannot support LS traffic on a FS root port */
506 [ - + ]: 185636 : if ((hcd->fops->speed(hcd, dwc_otg_urb->priv) == USB_SPEED_LOW) &&
507 [ # # ]: 0 : (hcd->core_if->hwcfg2.b.fs_phy_type == 1) &&
508 : : (hcd->core_if->hwcfg2.b.hs_phy_type == 1)) {
509 : 0 : hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
510 [ # # ]: 0 : if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED) {
511 : : return -DWC_E_NO_DEVICE;
512 : : }
513 : : }
514 : :
515 : 185636 : qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
516 [ - + ]: 185636 : if (qtd == NULL) {
517 : 0 : DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
518 : 0 : return -DWC_E_NO_MEMORY;
519 : : }
520 : : #ifdef DEBUG /* integrity checks (Broadcom) */
521 : : if (qtd->urb == NULL) {
522 : : DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
523 : : return -DWC_E_NO_MEMORY;
524 : : }
525 : : if (qtd->urb->priv == NULL) {
526 : : DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
527 : : return -DWC_E_NO_MEMORY;
528 : : }
529 : : #endif
530 : 185636 : intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
531 [ + + + - ]: 185636 : if(!intr_mask.b.sofintr || fiq_enable) needs_scheduling = 1;
532 [ - + # # ]: 185636 : if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
533 : : /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
534 : : needs_scheduling = 0;
535 : :
536 : 185636 : retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
537 : : // creates a new queue in ep_handle if it doesn't exist already
538 [ - + ]: 185636 : if (retval < 0) {
539 : 0 : DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
540 : : "Error status %d\n", retval);
541 : : dwc_otg_hcd_qtd_free(qtd);
542 : 0 : return retval;
543 : : }
544 : :
545 [ + - ]: 185636 : if(needs_scheduling) {
546 : 185636 : tr_type = dwc_otg_hcd_select_transactions(hcd);
547 [ + + ]: 185636 : if (tr_type != DWC_OTG_TRANSACTION_NONE) {
548 : 89114 : dwc_otg_hcd_queue_transactions(hcd, tr_type);
549 : : }
550 : : }
551 : 185636 : return retval;
552 : : }
553 : :
554 : 1038 : int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
555 : : dwc_otg_hcd_urb_t * dwc_otg_urb)
556 : : {
557 : : dwc_otg_qh_t *qh;
558 : : dwc_otg_qtd_t *urb_qtd;
559 [ - + ]: 1038 : BUG_ON(!hcd);
560 [ - + ]: 1038 : BUG_ON(!dwc_otg_urb);
561 : :
562 : : #ifdef DEBUG /* integrity checks (Broadcom) */
563 : :
564 : : if (hcd == NULL) {
565 : : DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
566 : : return -DWC_E_INVALID;
567 : : }
568 : : if (dwc_otg_urb == NULL) {
569 : : DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
570 : : return -DWC_E_INVALID;
571 : : }
572 : : if (dwc_otg_urb->qtd == NULL) {
573 : : DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
574 : : return -DWC_E_INVALID;
575 : : }
576 : : urb_qtd = dwc_otg_urb->qtd;
577 : : BUG_ON(!urb_qtd);
578 : : if (urb_qtd->qh == NULL) {
579 : : DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
580 : : return -DWC_E_INVALID;
581 : : }
582 : : #else
583 : 1038 : urb_qtd = dwc_otg_urb->qtd;
584 [ - + ]: 1038 : BUG_ON(!urb_qtd);
585 : : #endif
586 : 1038 : qh = urb_qtd->qh;
587 [ - + ]: 1038 : BUG_ON(!qh);
588 : : if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
589 : : if (urb_qtd->in_process) {
590 : : dump_channel_info(hcd, qh);
591 : : }
592 : : }
593 : : #ifdef DEBUG /* integrity checks (Broadcom) */
594 : : if (hcd->core_if == NULL) {
595 : : DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
596 : : return -DWC_E_INVALID;
597 : : }
598 : : #endif
599 [ + + + + ]: 1038 : if (urb_qtd->in_process && qh->channel) {
600 : : /* The QTD is in process (it has been assigned to a channel). */
601 [ + - ]: 114 : if (hcd->flags.b.port_connect_status) {
602 : 114 : int n = qh->channel->hc_num;
603 : : /*
604 : : * If still connected (i.e. in host mode), halt the
605 : : * channel so it can be used for other transfers. If
606 : : * no longer connected, the host registers can't be
607 : : * written to halt the channel since the core is in
608 : : * device mode.
609 : : */
610 : : /* In FIQ FSM mode, we need to shut down carefully.
611 : : * The FIQ may attempt to restart a disabled channel */
612 [ - + # # ]: 114 : if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) {
613 : : int retries = 3;
614 : : int running = 0;
615 : : enum fiq_fsm_state state;
616 : :
617 : 0 : local_fiq_disable();
618 : 0 : fiq_fsm_spin_lock(&hcd->fiq_state->lock);
619 : 0 : qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
620 : 0 : qh->channel->halt_pending = 1;
621 [ # # ]: 0 : if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
622 : : hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
623 : 0 : hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
624 : 0 : fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
625 : 0 : local_fiq_enable();
626 : :
627 [ # # ]: 0 : if (dwc_qh_is_non_per(qh)) {
628 : : do {
629 : 0 : state = READ_ONCE(hcd->fiq_state->channel[n].fsm);
630 : : running = (state != FIQ_NP_SPLIT_DONE) &&
631 : 0 : (state != FIQ_NP_SPLIT_LS_ABORTED) &&
632 : : (state != FIQ_NP_SPLIT_HS_ABORTED);
633 [ # # ]: 0 : if (!running)
634 : : break;
635 : 0 : udelay(125);
636 [ # # ]: 0 : } while(--retries);
637 [ # # ]: 0 : if (!retries)
638 : 0 : DWC_WARN("Timed out waiting for FSM NP transfer to complete on %d",
639 : : qh->channel->hc_num);
640 : : }
641 : : } else {
642 : 114 : dwc_otg_hc_halt(hcd->core_if, qh->channel,
643 : : DWC_OTG_HC_XFER_URB_DEQUEUE);
644 : : }
645 : : }
646 : : }
647 : :
648 : : /*
649 : : * Free the QTD and clean up the associated QH. Leave the QH in the
650 : : * schedule if it has any remaining QTDs.
651 : : */
652 : :
653 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
654 : : "delete %sQueue handler\n",
655 : : hcd->core_if->dma_desc_enable?"DMA ":"");
656 [ + - ]: 1038 : if (!hcd->core_if->dma_desc_enable) {
657 : 1038 : uint8_t b = urb_qtd->in_process;
658 [ + - - + : 1038 : if (nak_holdoff && qh->do_split && dwc_qh_is_non_per(qh))
# # ]
659 : 0 : qh->nak_frame = 0xFFFF;
660 : 1038 : dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
661 [ + + ]: 1038 : if (b) {
662 : 1018 : dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
663 : 1018 : qh->channel = NULL;
664 [ + - ]: 20 : } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
665 : 20 : dwc_otg_hcd_qh_remove(hcd, qh);
666 : : }
667 : : } else {
668 : 0 : dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
669 : : }
670 : 1038 : return 0;
671 : : }
672 : :
673 : 5656 : int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
674 : : int retry)
675 : : {
676 : : dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
677 : : int retval = 0;
678 : : dwc_irqflags_t flags;
679 : :
680 [ + - ]: 5656 : if (retry < 0) {
681 : : retval = -DWC_E_INVALID;
682 : : goto done;
683 : : }
684 : :
685 [ + + ]: 5656 : if (!qh) {
686 : : retval = -DWC_E_INVALID;
687 : : goto done;
688 : : }
689 : :
690 : 1616 : DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
691 : :
692 [ - + # # ]: 3232 : while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
693 : 0 : DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
694 : 0 : retry--;
695 : 0 : dwc_msleep(5);
696 : 0 : DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
697 : : }
698 : :
699 : 1616 : dwc_otg_hcd_qh_remove(hcd, qh);
700 : :
701 : 1616 : DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
702 : : /*
703 : : * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
704 : : * and qh_free to prevent stack dump on DWC_DMA_FREE() with
705 : : * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
706 : : * and dwc_otg_hcd_frame_list_alloc().
707 : : */
708 : 1616 : dwc_otg_hcd_qh_free(hcd, qh);
709 : :
710 : : done:
711 : 5656 : return retval;
712 : : }
713 : :
714 : : #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
715 : 0 : int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
716 : : {
717 : : int retval = 0;
718 : : dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
719 [ # # ]: 0 : if (!qh)
720 : : return -DWC_E_INVALID;
721 : :
722 : 0 : qh->data_toggle = DWC_OTG_HC_PID_DATA0;
723 : 0 : return retval;
724 : : }
725 : : #endif
726 : :
727 : : /**
728 : : * HCD Callback structure for handling mode switching.
729 : : */
730 : : static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
731 : : .start = dwc_otg_hcd_start_cb,
732 : : .stop = dwc_otg_hcd_stop_cb,
733 : : .disconnect = dwc_otg_hcd_disconnect_cb,
734 : : .session_start = dwc_otg_hcd_session_start_cb,
735 : : .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
736 : : #ifdef CONFIG_USB_DWC_OTG_LPM
737 : : .sleep = dwc_otg_hcd_sleep_cb,
738 : : #endif
739 : : .p = 0,
740 : : };
741 : :
742 : : /**
743 : : * Reset tasklet function
744 : : */
745 : 0 : static void reset_tasklet_func(void *data)
746 : : {
747 : : dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
748 : 0 : dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
749 : : hprt0_data_t hprt0;
750 : :
751 : : DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
752 : :
753 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
754 : 0 : hprt0.b.prtrst = 1;
755 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
756 : 0 : dwc_mdelay(60);
757 : :
758 : 0 : hprt0.b.prtrst = 0;
759 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
760 : 0 : dwc_otg_hcd->flags.b.port_reset_change = 1;
761 : 0 : }
762 : :
763 : 168180 : static void completion_tasklet_func(void *ptr)
764 : : {
765 : : dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr;
766 : : struct urb *urb;
767 : : urb_tq_entry_t *item;
768 : : dwc_irqflags_t flags;
769 : :
770 : : /* This could just be spin_lock_irq */
771 : 168180 : DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
772 [ + + ]: 517974 : while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) {
773 : : item = DWC_TAILQ_FIRST(&hcd->completed_urb_list);
774 : 181614 : urb = item->urb;
775 [ + + ]: 181614 : DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item,
776 : : urb_tq_entries);
777 : 181614 : DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
778 : 181614 : DWC_FREE(item);
779 : :
780 : 181614 : usb_hcd_giveback_urb(hcd->priv, urb, urb->status);
781 : :
782 : :
783 : 181614 : DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
784 : : }
785 : 168180 : DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
786 : 168180 : return;
787 : : }
788 : :
789 : 0 : static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
790 : : {
791 : : dwc_list_link_t *item;
792 : : dwc_otg_qh_t *qh;
793 : : dwc_irqflags_t flags;
794 : :
795 [ # # ]: 0 : if (!qh_list->next) {
796 : : /* The list hasn't been initialized yet. */
797 : 0 : return;
798 : : }
799 : : /*
800 : : * Hold spinlock here. Not needed in that case if bellow
801 : : * function is being called from ISR
802 : : */
803 : 0 : DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
804 : : /* Ensure there are no QTDs or URBs left. */
805 : 0 : kill_urbs_in_qh_list(hcd, qh_list);
806 : 0 : DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
807 : :
808 [ # # ]: 0 : DWC_LIST_FOREACH(item, qh_list) {
809 : 0 : qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
810 : 0 : dwc_otg_hcd_qh_remove_and_free(hcd, qh);
811 : : }
812 : : }
813 : :
814 : : /**
815 : : * Exit from Hibernation if Host did not detect SRP from connected SRP capable
816 : : * Device during SRP time by host power up.
817 : : */
818 : 0 : void dwc_otg_hcd_power_up(void *ptr)
819 : : {
820 : 0 : gpwrdn_data_t gpwrdn = {.d32 = 0 };
821 : : dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
822 : :
823 : 0 : DWC_PRINTF("%s called\n", __FUNCTION__);
824 : :
825 [ # # ]: 0 : if (!core_if->hibernation_suspend) {
826 : 0 : DWC_PRINTF("Already exited from Hibernation\n");
827 : 0 : return;
828 : : }
829 : :
830 : : /* Switch on the voltage to the core */
831 : 0 : gpwrdn.b.pwrdnswtch = 1;
832 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
833 : 0 : dwc_udelay(10);
834 : :
835 : : /* Reset the core */
836 : 0 : gpwrdn.d32 = 0;
837 : 0 : gpwrdn.b.pwrdnrstn = 1;
838 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
839 : 0 : dwc_udelay(10);
840 : :
841 : : /* Disable power clamps */
842 : 0 : gpwrdn.d32 = 0;
843 : 0 : gpwrdn.b.pwrdnclmp = 1;
844 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
845 : :
846 : : /* Remove reset the core signal */
847 : 0 : gpwrdn.d32 = 0;
848 : 0 : gpwrdn.b.pwrdnrstn = 1;
849 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
850 : 0 : dwc_udelay(10);
851 : :
852 : : /* Disable PMU interrupt */
853 : 0 : gpwrdn.d32 = 0;
854 : 0 : gpwrdn.b.pmuintsel = 1;
855 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
856 : :
857 : 0 : core_if->hibernation_suspend = 0;
858 : :
859 : : /* Disable PMU */
860 : 0 : gpwrdn.d32 = 0;
861 : 0 : gpwrdn.b.pmuactv = 1;
862 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
863 : 0 : dwc_udelay(10);
864 : :
865 : : /* Enable VBUS */
866 : 0 : gpwrdn.d32 = 0;
867 : 0 : gpwrdn.b.dis_vbus = 1;
868 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
869 : :
870 : 0 : core_if->op_state = A_HOST;
871 : 0 : dwc_otg_core_init(core_if);
872 : 0 : dwc_otg_enable_global_interrupts(core_if);
873 : : cil_hcd_start(core_if);
874 : : }
875 : :
876 : 0 : void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num)
877 : : {
878 : 0 : struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
879 : 0 : struct fiq_dma_blob *blob = hcd->fiq_dmab;
880 : : int i;
881 : :
882 : 0 : st->fsm = FIQ_PASSTHROUGH;
883 : 0 : st->hcchar_copy.d32 = 0;
884 : 0 : st->hcsplt_copy.d32 = 0;
885 : 0 : st->hcint_copy.d32 = 0;
886 : 0 : st->hcintmsk_copy.d32 = 0;
887 : 0 : st->hctsiz_copy.d32 = 0;
888 : 0 : st->hcdma_copy.d32 = 0;
889 : 0 : st->nr_errors = 0;
890 : 0 : st->hub_addr = 0;
891 : 0 : st->port_addr = 0;
892 : 0 : st->expected_uframe = 0;
893 : 0 : st->nrpackets = 0;
894 : 0 : st->dma_info.index = 0;
895 [ # # ]: 0 : for (i = 0; i < 6; i++)
896 : 0 : st->dma_info.slot_len[i] = 255;
897 : 0 : st->hs_isoc_info.index = 0;
898 : 0 : st->hs_isoc_info.iso_desc = NULL;
899 : 0 : st->hs_isoc_info.nrframes = 0;
900 : :
901 : 0 : DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128);
902 : 0 : }
903 : :
904 : : /**
905 : : * Frees secondary storage associated with the dwc_otg_hcd structure contained
906 : : * in the struct usb_hcd field.
907 : : */
908 : 0 : static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
909 : : {
910 : : struct device *dev = dwc_otg_hcd_to_dev(dwc_otg_hcd);
911 : : int i;
912 : :
913 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
914 : :
915 : : del_timers(dwc_otg_hcd);
916 : :
917 : : /* Free memory for QH/QTD lists */
918 : 0 : qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
919 : 0 : qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
920 : 0 : qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
921 : 0 : qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
922 : 0 : qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
923 : 0 : qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
924 : :
925 : : /* Free memory for the host channels. */
926 [ # # ]: 0 : for (i = 0; i < MAX_EPS_CHANNELS; i++) {
927 : 0 : dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
928 : :
929 : : #ifdef DEBUG
930 : : if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
931 : : DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
932 : : }
933 : : #endif
934 [ # # ]: 0 : if (hc != NULL) {
935 : : DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
936 : : i, hc);
937 : 0 : DWC_FREE(hc);
938 : : }
939 : : }
940 : :
941 [ # # ]: 0 : if (dwc_otg_hcd->core_if->dma_enable) {
942 [ # # ]: 0 : if (dwc_otg_hcd->status_buf_dma) {
943 : 0 : DWC_DMA_FREE(dev, DWC_OTG_HCD_STATUS_BUF_SIZE,
944 : : dwc_otg_hcd->status_buf,
945 : : dwc_otg_hcd->status_buf_dma);
946 : : }
947 [ # # ]: 0 : } else if (dwc_otg_hcd->status_buf != NULL) {
948 : 0 : DWC_FREE(dwc_otg_hcd->status_buf);
949 : : }
950 : 0 : DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
951 : : /* Set core_if's lock pointer to NULL */
952 : 0 : dwc_otg_hcd->core_if->lock = NULL;
953 : :
954 : 0 : DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
955 : 0 : DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
956 : 0 : DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet);
957 : 0 : DWC_DMA_FREE(dev, 16, dwc_otg_hcd->fiq_state->dummy_send,
958 : : dwc_otg_hcd->fiq_state->dummy_send_dma);
959 : 0 : DWC_FREE(dwc_otg_hcd->fiq_state);
960 : :
961 : : #ifdef DWC_DEV_SRPCAP
962 : : if (dwc_otg_hcd->core_if->power_down == 2 &&
963 : : dwc_otg_hcd->core_if->pwron_timer) {
964 : : DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
965 : : }
966 : : #endif
967 : 0 : DWC_FREE(dwc_otg_hcd);
968 : 0 : }
969 : :
970 : 404 : int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
971 : : {
972 : : struct device *dev = dwc_otg_hcd_to_dev(hcd);
973 : : int retval = 0;
974 : : int num_channels;
975 : : int i;
976 : : dwc_hc_t *channel;
977 : :
978 : : #if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
979 : : DWC_SPINLOCK_ALLOC_LINUX_DEBUG(hcd->lock);
980 : : #else
981 : 404 : hcd->lock = DWC_SPINLOCK_ALLOC();
982 : : #endif
983 : : DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
984 : : hcd, core_if);
985 [ - + ]: 404 : if (!hcd->lock) {
986 : 0 : DWC_ERROR("Could not allocate lock for pcd");
987 : 0 : DWC_FREE(hcd);
988 : : retval = -DWC_E_NO_MEMORY;
989 : 0 : goto out;
990 : : }
991 : 404 : hcd->core_if = core_if;
992 : :
993 : : /* Register the HCD CIL Callbacks */
994 : 404 : dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
995 : : &hcd_cil_callbacks, hcd);
996 : :
997 : : /* Initialize the non-periodic schedule. */
998 : 404 : DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
999 : 404 : DWC_LIST_INIT(&hcd->non_periodic_sched_active);
1000 : :
1001 : : /* Initialize the periodic schedule. */
1002 : 404 : DWC_LIST_INIT(&hcd->periodic_sched_inactive);
1003 : 404 : DWC_LIST_INIT(&hcd->periodic_sched_ready);
1004 : 404 : DWC_LIST_INIT(&hcd->periodic_sched_assigned);
1005 : 404 : DWC_LIST_INIT(&hcd->periodic_sched_queued);
1006 : 404 : DWC_TAILQ_INIT(&hcd->completed_urb_list);
1007 : : /*
1008 : : * Create a host channel descriptor for each host channel implemented
1009 : : * in the controller. Initialize the channel descriptor array.
1010 : : */
1011 : 404 : DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
1012 : 404 : num_channels = hcd->core_if->core_params->host_channels;
1013 : 404 : DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
1014 [ + + ]: 3636 : for (i = 0; i < num_channels; i++) {
1015 : 3232 : channel = DWC_ALLOC(sizeof(dwc_hc_t));
1016 [ - + ]: 3232 : if (channel == NULL) {
1017 : : retval = -DWC_E_NO_MEMORY;
1018 : 0 : DWC_ERROR("%s: host channel allocation failed\n",
1019 : : __func__);
1020 : 0 : dwc_otg_hcd_free(hcd);
1021 : 0 : goto out;
1022 : : }
1023 : 3232 : channel->hc_num = i;
1024 : 3232 : hcd->hc_ptr_array[i] = channel;
1025 : : #ifdef DEBUG
1026 : : hcd->core_if->hc_xfer_timer[i] =
1027 : : DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
1028 : : &hcd->core_if->hc_xfer_info[i]);
1029 : : #endif
1030 : : DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
1031 : : channel);
1032 : : }
1033 : :
1034 [ + - ]: 404 : if (fiq_enable) {
1035 : 404 : hcd->fiq_state = DWC_ALLOC(sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels));
1036 [ - + ]: 404 : if (!hcd->fiq_state) {
1037 : : retval = -DWC_E_NO_MEMORY;
1038 : 0 : DWC_ERROR("%s: cannot allocate fiq_state structure\n", __func__);
1039 : 0 : dwc_otg_hcd_free(hcd);
1040 : 0 : goto out;
1041 : : }
1042 : 404 : DWC_MEMSET(hcd->fiq_state, 0, (sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels)));
1043 : :
1044 : : #ifdef CONFIG_ARM64
1045 : : spin_lock_init(&hcd->fiq_state->lock);
1046 : : #endif
1047 : :
1048 [ + + ]: 3636 : for (i = 0; i < num_channels; i++) {
1049 : 3232 : hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH;
1050 : : }
1051 : 404 : hcd->fiq_state->dummy_send = DWC_DMA_ALLOC_ATOMIC(dev, 16,
1052 : : &hcd->fiq_state->dummy_send_dma);
1053 : :
1054 : 404 : hcd->fiq_stack = DWC_ALLOC(sizeof(struct fiq_stack));
1055 [ - + ]: 404 : if (!hcd->fiq_stack) {
1056 : : retval = -DWC_E_NO_MEMORY;
1057 : 0 : DWC_ERROR("%s: cannot allocate fiq_stack structure\n", __func__);
1058 : 0 : dwc_otg_hcd_free(hcd);
1059 : 0 : goto out;
1060 : : }
1061 : 404 : hcd->fiq_stack->magic1 = 0xDEADBEEF;
1062 : 404 : hcd->fiq_stack->magic2 = 0xD00DFEED;
1063 : 404 : hcd->fiq_state->gintmsk_saved.d32 = ~0;
1064 : 404 : hcd->fiq_state->haintmsk_saved.b2.chint = ~0;
1065 : :
1066 : : /* This bit is terrible and uses no API, but necessary. The FIQ has no concept of DMA pools
1067 : : * (and if it did, would be a lot slower). This allocates a chunk of memory (~9kiB for 8 host channels)
1068 : : * for use as transaction bounce buffers in a 2-D array. Our access into this chunk is done by some
1069 : : * moderately readable array casts.
1070 : : */
1071 : 404 : hcd->fiq_dmab = DWC_DMA_ALLOC(dev, (sizeof(struct fiq_dma_channel) * num_channels), &hcd->fiq_state->dma_base);
1072 : 404 : DWC_WARN("FIQ DMA bounce buffers: virt = %px dma = %pad len=%zu",
1073 : : hcd->fiq_dmab, &hcd->fiq_state->dma_base,
1074 : : sizeof(struct fiq_dma_channel) * num_channels);
1075 : :
1076 : 404 : DWC_MEMSET(hcd->fiq_dmab, 0x6b, 9024);
1077 : :
1078 : : /* pointer for debug in fiq_print */
1079 : 404 : hcd->fiq_state->fiq_dmab = hcd->fiq_dmab;
1080 [ - + ]: 404 : if (fiq_fsm_enable) {
1081 : : int i;
1082 [ # # ]: 0 : for (i=0; i < hcd->core_if->core_params->host_channels; i++) {
1083 : 0 : dwc_otg_cleanup_fiq_channel(hcd, i);
1084 : : }
1085 [ # # # # : 0 : DWC_PRINTF("FIQ FSM acceleration enabled for :\n%s%s%s%s",
# # # # ]
1086 : 0 : (fiq_fsm_mask & 0x1) ? "Non-periodic Split Transactions\n" : "",
1087 : 0 : (fiq_fsm_mask & 0x2) ? "Periodic Split Transactions\n" : "",
1088 : 0 : (fiq_fsm_mask & 0x4) ? "High-Speed Isochronous Endpoints\n" : "",
1089 : 0 : (fiq_fsm_mask & 0x8) ? "Interrupt/Control Split Transaction hack enabled\n" : "");
1090 : : }
1091 : : }
1092 : :
1093 : : /* Initialize the Connection timeout timer. */
1094 : 404 : hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
1095 : : dwc_otg_hcd_connect_timeout, 0);
1096 : :
1097 [ - + ]: 404 : printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
1098 [ + - ]: 404 : if (microframe_schedule)
1099 : 404 : init_hcd_usecs(hcd);
1100 : :
1101 : : /* Initialize reset tasklet. */
1102 : 404 : hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
1103 : :
1104 : 404 : hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet",
1105 : : completion_tasklet_func, hcd);
1106 : : #ifdef DWC_DEV_SRPCAP
1107 : : if (hcd->core_if->power_down == 2) {
1108 : : /* Initialize Power on timer for Host power up in case hibernation */
1109 : : hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
1110 : : dwc_otg_hcd_power_up, core_if);
1111 : : }
1112 : : #endif
1113 : :
1114 : : /*
1115 : : * Allocate space for storing data on status transactions. Normally no
1116 : : * data is sent, but this space acts as a bit bucket. This must be
1117 : : * done after usb_add_hcd since that function allocates the DMA buffer
1118 : : * pool.
1119 : : */
1120 [ + - ]: 404 : if (hcd->core_if->dma_enable) {
1121 : 404 : hcd->status_buf =
1122 : 404 : DWC_DMA_ALLOC(dev, DWC_OTG_HCD_STATUS_BUF_SIZE,
1123 : : &hcd->status_buf_dma);
1124 : : } else {
1125 : 0 : hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
1126 : : }
1127 [ - + ]: 404 : if (!hcd->status_buf) {
1128 : : retval = -DWC_E_NO_MEMORY;
1129 : 0 : DWC_ERROR("%s: status_buf allocation failed\n", __func__);
1130 : 0 : dwc_otg_hcd_free(hcd);
1131 : 0 : goto out;
1132 : : }
1133 : :
1134 : 404 : hcd->otg_port = 1;
1135 : 404 : hcd->frame_list = NULL;
1136 : 404 : hcd->frame_list_dma = 0;
1137 : 404 : hcd->periodic_qh_count = 0;
1138 : :
1139 : 404 : DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port));
1140 : : #ifdef FIQ_DEBUG
1141 : : DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc));
1142 : : #endif
1143 : :
1144 : : out:
1145 : 404 : return retval;
1146 : : }
1147 : :
1148 : 0 : void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
1149 : : {
1150 : : /* Turn off all host-specific interrupts. */
1151 : 0 : dwc_otg_disable_host_interrupts(hcd->core_if);
1152 : :
1153 : 0 : dwc_otg_hcd_free(hcd);
1154 : 0 : }
1155 : :
1156 : : /**
1157 : : * Initializes dynamic portions of the DWC_otg HCD state.
1158 : : */
1159 : 404 : static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
1160 : : {
1161 : : int num_channels;
1162 : : int i;
1163 : : dwc_hc_t *channel;
1164 : : dwc_hc_t *channel_tmp;
1165 : :
1166 : 404 : hcd->flags.d32 = 0;
1167 : :
1168 : 404 : hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
1169 [ - + ]: 404 : if (!microframe_schedule) {
1170 : 0 : hcd->non_periodic_channels = 0;
1171 : 0 : hcd->periodic_channels = 0;
1172 : : } else {
1173 : 404 : hcd->available_host_channels = hcd->core_if->core_params->host_channels;
1174 : : }
1175 : : /*
1176 : : * Put all channels in the free channel list and clean up channel
1177 : : * states.
1178 : : */
1179 [ - + ]: 404 : DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
1180 : : &hcd->free_hc_list, hc_list_entry) {
1181 [ # # # # ]: 0 : DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
1182 : : }
1183 : :
1184 : 404 : num_channels = hcd->core_if->core_params->host_channels;
1185 [ + + ]: 3636 : for (i = 0; i < num_channels; i++) {
1186 : 3232 : channel = hcd->hc_ptr_array[i];
1187 [ + + ]: 3232 : DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
1188 : : hc_list_entry);
1189 : 3232 : dwc_otg_hc_cleanup(hcd->core_if, channel);
1190 : : }
1191 : :
1192 : : /* Initialize the DWC core for host mode operation. */
1193 : 404 : dwc_otg_core_host_init(hcd->core_if);
1194 : :
1195 : : /* Set core_if's lock pointer to the hcd->lock */
1196 : 404 : hcd->core_if->lock = hcd->lock;
1197 : 404 : }
1198 : :
1199 : : /**
1200 : : * Assigns transactions from a QTD to a free host channel and initializes the
1201 : : * host channel to perform the transactions. The host channel is removed from
1202 : : * the free list.
1203 : : *
1204 : : * @param hcd The HCD state structure.
1205 : : * @param qh Transactions from the first QTD for this QH are selected and
1206 : : * assigned to a free host channel.
1207 : : */
1208 : 227670956 : static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
1209 : : {
1210 : : dwc_hc_t *hc;
1211 : : dwc_otg_qtd_t *qtd;
1212 : : dwc_otg_hcd_urb_t *urb;
1213 : : void* ptr = NULL;
1214 : : uint16_t wLength;
1215 : : uint32_t intr_enable;
1216 : : unsigned long flags;
1217 : 227670956 : gintmsk_data_t gintmsk = { .d32 = 0, };
1218 : : struct device *dev = dwc_otg_hcd_to_dev(hcd);
1219 : :
1220 : 227670956 : qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
1221 : :
1222 : 227670956 : urb = qtd->urb;
1223 : :
1224 : : DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
1225 : :
1226 [ - + # # ]: 227670956 : if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info))
1227 : 0 : urb->actual_length = urb->length;
1228 : :
1229 : :
1230 : 227670956 : hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
1231 : :
1232 : : /* Remove the host channel from the free list. */
1233 [ - + + - ]: 227670956 : DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
1234 : :
1235 : 227670956 : qh->channel = hc;
1236 : :
1237 : 227670956 : qtd->in_process = 1;
1238 : :
1239 : : /*
1240 : : * Use usb_pipedevice to determine device address. This address is
1241 : : * 0 before the SET_ADDRESS command and the correct address afterward.
1242 : : */
1243 : 227670956 : hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
1244 : 227670956 : hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
1245 : 227670956 : hc->speed = qh->dev_speed;
1246 : 227670956 : hc->max_packet = dwc_max_packet(qh->maxp);
1247 : :
1248 : 227670956 : hc->xfer_started = 0;
1249 : 227670956 : hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
1250 : 227670956 : hc->error_state = (qtd->error_count > 0);
1251 : 227670956 : hc->halt_on_queue = 0;
1252 : 227670956 : hc->halt_pending = 0;
1253 : 227670956 : hc->requests = 0;
1254 : :
1255 : : /*
1256 : : * The following values may be modified in the transfer type section
1257 : : * below. The xfer_len value may be reduced when the transfer is
1258 : : * started to accommodate the max widths of the XferSize and PktCnt
1259 : : * fields in the HCTSIZn register.
1260 : : */
1261 : :
1262 : 227670956 : hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
1263 [ + + ]: 227670956 : if (hc->ep_is_in) {
1264 : 227616306 : hc->do_ping = 0;
1265 : : } else {
1266 : 54650 : hc->do_ping = qh->ping_state;
1267 : : }
1268 : :
1269 : 227670956 : hc->data_pid_start = qh->data_toggle;
1270 : 227670956 : hc->multi_count = 1;
1271 : :
1272 [ + - ]: 227670956 : if (hcd->core_if->dma_enable) {
1273 : 227670956 : hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
1274 : :
1275 : : /* For non-dword aligned case */
1276 [ + + ]: 227670956 : if (((unsigned long)hc->xfer_buff & 0x3)
1277 [ + - ]: 45930 : && !hcd->core_if->dma_desc_enable) {
1278 : 45930 : ptr = (uint8_t *) urb->buf + urb->actual_length;
1279 : : }
1280 : : } else {
1281 : 0 : hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
1282 : : }
1283 : 227670956 : hc->xfer_len = urb->length - urb->actual_length;
1284 : 227670956 : hc->xfer_count = 0;
1285 : :
1286 : : /*
1287 : : * Set the split attributes
1288 : : */
1289 : 227670956 : hc->do_split = 0;
1290 [ - + ]: 227670956 : if (qh->do_split) {
1291 : : uint32_t hub_addr, port_addr;
1292 : 0 : hc->do_split = 1;
1293 : 0 : hc->start_pkt_count = 1;
1294 : 0 : hc->xact_pos = qtd->isoc_split_pos;
1295 : : /* We don't need to do complete splits anymore */
1296 : : // if(fiq_fsm_enable)
1297 : : if (0)
1298 : : hc->complete_split = qtd->complete_split = 0;
1299 : : else
1300 : 0 : hc->complete_split = qtd->complete_split;
1301 : :
1302 : 0 : hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
1303 : 0 : hc->hub_addr = (uint8_t) hub_addr;
1304 : 0 : hc->port_addr = (uint8_t) port_addr;
1305 : : }
1306 : :
1307 [ + + + - : 227670956 : switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
- ]
1308 : : case UE_CONTROL:
1309 : 118454 : hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
1310 [ + + + - ]: 118454 : switch (qtd->control_phase) {
1311 : : case DWC_OTG_CONTROL_SETUP:
1312 : : DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
1313 : 45706 : hc->do_ping = 0;
1314 : 45706 : hc->ep_is_in = 0;
1315 : 45706 : hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
1316 [ + - ]: 45706 : if (hcd->core_if->dma_enable) {
1317 : 45706 : hc->xfer_buff = (uint8_t *) urb->setup_dma;
1318 : : } else {
1319 : 0 : hc->xfer_buff = (uint8_t *) urb->setup_packet;
1320 : : }
1321 : 45706 : hc->xfer_len = 8;
1322 : : ptr = NULL;
1323 : 45706 : break;
1324 : : case DWC_OTG_CONTROL_DATA:
1325 : : DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
1326 : : /*
1327 : : * Hardware bug: small IN packets with length < 4
1328 : : * cause a 4-byte write to memory. We can only catch
1329 : : * the case where we know a short packet is going to be
1330 : : * returned in a control transfer, as the length is
1331 : : * specified in the setup packet. This is only an issue
1332 : : * for drivers that insist on packing a device's various
1333 : : * properties into a struct and querying them one at a
1334 : : * time (uvcvideo).
1335 : : * Force the use of align_buf so that the subsequent
1336 : : * memcpy puts the right number of bytes in the URB's
1337 : : * buffer.
1338 : : */
1339 : 28254 : wLength = ((uint16_t *)urb->setup_packet)[3];
1340 [ + + + + ]: 28254 : if (hc->ep_is_in && wLength < 4)
1341 : 404 : ptr = hc->xfer_buff;
1342 : :
1343 : 28254 : hc->data_pid_start = qtd->data_toggle;
1344 : 28254 : break;
1345 : : case DWC_OTG_CONTROL_STATUS:
1346 : : /*
1347 : : * Direction is opposite of data direction or IN if no
1348 : : * data.
1349 : : */
1350 : : DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
1351 [ + + ]: 44494 : if (urb->length == 0) {
1352 : 16240 : hc->ep_is_in = 1;
1353 : : } else {
1354 : 28254 : hc->ep_is_in =
1355 : : dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
1356 : : }
1357 [ + + ]: 44494 : if (hc->ep_is_in) {
1358 : 16644 : hc->do_ping = 0;
1359 : : }
1360 : :
1361 : 44494 : hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
1362 : :
1363 : 44494 : hc->xfer_len = 0;
1364 [ + - ]: 44494 : if (hcd->core_if->dma_enable) {
1365 : 44494 : hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
1366 : : } else {
1367 : 0 : hc->xfer_buff = (uint8_t *) hcd->status_buf;
1368 : : }
1369 : : ptr = NULL;
1370 : : break;
1371 : : }
1372 : : break;
1373 : : case UE_BULK:
1374 : 32442 : hc->ep_type = DWC_OTG_EP_TYPE_BULK;
1375 : 32442 : break;
1376 : : case UE_INTERRUPT:
1377 : 227520060 : hc->ep_type = DWC_OTG_EP_TYPE_INTR;
1378 : 227520060 : break;
1379 : : case UE_ISOCHRONOUS:
1380 : : {
1381 : : struct dwc_otg_hcd_iso_packet_desc *frame_desc;
1382 : :
1383 : 0 : hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
1384 : :
1385 [ # # ]: 0 : if (hcd->core_if->dma_desc_enable)
1386 : : break;
1387 : :
1388 : 0 : frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
1389 : :
1390 : 0 : frame_desc->status = 0;
1391 : :
1392 [ # # ]: 0 : if (hcd->core_if->dma_enable) {
1393 : 0 : hc->xfer_buff = (uint8_t *) urb->dma;
1394 : : } else {
1395 : 0 : hc->xfer_buff = (uint8_t *) urb->buf;
1396 : : }
1397 : 0 : hc->xfer_buff +=
1398 : 0 : frame_desc->offset + qtd->isoc_split_offset;
1399 : 0 : hc->xfer_len =
1400 : 0 : frame_desc->length - qtd->isoc_split_offset;
1401 : :
1402 : : /* For non-dword aligned buffers */
1403 [ # # ]: 0 : if (((unsigned long)hc->xfer_buff & 0x3)
1404 [ # # ]: 0 : && hcd->core_if->dma_enable) {
1405 : 0 : ptr =
1406 : 0 : (uint8_t *) urb->buf + frame_desc->offset +
1407 : 0 : qtd->isoc_split_offset;
1408 : : } else
1409 : : ptr = NULL;
1410 : :
1411 [ # # ]: 0 : if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
1412 [ # # ]: 0 : if (hc->xfer_len <= 188) {
1413 : 0 : hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
1414 : : } else {
1415 : 0 : hc->xact_pos =
1416 : : DWC_HCSPLIT_XACTPOS_BEGIN;
1417 : : }
1418 : : }
1419 : : }
1420 : : break;
1421 : : }
1422 : : /* non DWORD-aligned buffer case */
1423 [ + + ]: 227670956 : if (ptr) {
1424 : : uint32_t buf_size;
1425 [ + - ]: 32846 : if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
1426 : 32846 : buf_size = hcd->core_if->core_params->max_transfer_size;
1427 : : } else {
1428 : : buf_size = 4096;
1429 : : }
1430 [ + + ]: 32846 : if (!qh->dw_align_buf) {
1431 : 1212 : qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(dev, buf_size,
1432 : : &qh->dw_align_buf_dma);
1433 [ - + ]: 1212 : if (!qh->dw_align_buf) {
1434 : 0 : DWC_ERROR
1435 : : ("%s: Failed to allocate memory to handle "
1436 : : "non-dword aligned buffer case\n",
1437 : : __func__);
1438 : 227670948 : return;
1439 : : }
1440 : : }
1441 [ + + ]: 32846 : if (!hc->ep_is_in) {
1442 : 20958 : dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
1443 : : }
1444 : 32846 : hc->align_buff = qh->dw_align_buf_dma;
1445 : : } else {
1446 : 227638110 : hc->align_buff = 0;
1447 : : }
1448 : :
1449 [ + + ]: 227670956 : if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
1450 : : hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
1451 : : /*
1452 : : * This value may be modified when the transfer is started to
1453 : : * reflect the actual transfer length.
1454 : : */
1455 : 227520060 : hc->multi_count = dwc_hb_mult(qh->maxp);
1456 : : }
1457 : :
1458 [ - + ]: 227670956 : if (hcd->core_if->dma_desc_enable)
1459 : 0 : hc->desc_list_addr = qh->desc_list_dma;
1460 : :
1461 : 227670956 : dwc_otg_hc_init(hcd->core_if, hc);
1462 : :
1463 : 227670950 : local_irq_save(flags);
1464 : :
1465 [ + - ]: 227670948 : if (fiq_enable) {
1466 : 227670948 : local_fiq_disable();
1467 : 227670948 : fiq_fsm_spin_lock(&hcd->fiq_state->lock);
1468 : : }
1469 : :
1470 : : /* Enable the top level host channel interrupt. */
1471 : 227670948 : intr_enable = (1 << hc->hc_num);
1472 : 227670948 : DWC_MODIFY_REG32(&hcd->core_if->host_if->host_global_regs->haintmsk, 0, intr_enable);
1473 : :
1474 : : /* Make sure host channel interrupts are enabled. */
1475 : 227670948 : gintmsk.b.hcintr = 1;
1476 : 227670948 : DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
1477 : :
1478 [ + - ]: 227670948 : if (fiq_enable) {
1479 : 227670948 : fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
1480 : 227670948 : local_fiq_enable();
1481 : : }
1482 : :
1483 [ + - ]: 455341896 : local_irq_restore(flags);
1484 : 227670948 : hc->qh = qh;
1485 : : }
1486 : :
1487 : :
1488 : : /**
1489 : : * fiq_fsm_transaction_suitable() - Test a QH for compatibility with the FIQ
1490 : : * @hcd: Pointer to the dwc_otg_hcd struct
1491 : : * @qh: pointer to the endpoint's queue head
1492 : : *
1493 : : * Transaction start/end control flow is grafted onto the existing dwc_otg
1494 : : * mechanisms, to avoid spaghettifying the functions more than they already are.
1495 : : * This function's eligibility check is altered by debug parameter.
1496 : : *
1497 : : * Returns: 0 for unsuitable, 1 implies the FIQ can be enabled for this transaction.
1498 : : */
1499 : :
1500 : 0 : int fiq_fsm_transaction_suitable(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
1501 : : {
1502 [ # # ]: 0 : if (qh->do_split) {
1503 [ # # # ]: 0 : switch (qh->ep_type) {
1504 : : case UE_CONTROL:
1505 : : case UE_BULK:
1506 [ # # ]: 0 : if (fiq_fsm_mask & (1 << 0))
1507 : : return 1;
1508 : : break;
1509 : : case UE_INTERRUPT:
1510 : : case UE_ISOCHRONOUS:
1511 [ # # ]: 0 : if (fiq_fsm_mask & (1 << 1))
1512 : : return 1;
1513 : : break;
1514 : : default:
1515 : : break;
1516 : : }
1517 [ # # ]: 0 : } else if (qh->ep_type == UE_ISOCHRONOUS) {
1518 [ # # ]: 0 : if (fiq_fsm_mask & (1 << 2)) {
1519 : : /* ISOCH support. We test for compatibility:
1520 : : * - DWORD aligned buffers
1521 : : * - Must be at least 2 transfers (otherwise pointless to use the FIQ)
1522 : : * If yes, then the fsm enqueue function will handle the state machine setup.
1523 : : */
1524 : 0 : dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
1525 : 0 : dwc_otg_hcd_urb_t *urb = qtd->urb;
1526 : : dwc_dma_t ptr;
1527 : : int i;
1528 : :
1529 [ # # ]: 0 : if (urb->packet_count < 2)
1530 : : return 0;
1531 [ # # ]: 0 : for (i = 0; i < urb->packet_count; i++) {
1532 : 0 : ptr = urb->dma + urb->iso_descs[i].offset;
1533 [ # # ]: 0 : if (ptr & 0x3)
1534 : : return 0;
1535 : : }
1536 : : return 1;
1537 : : }
1538 : : }
1539 : 0 : return 0;
1540 : : }
1541 : :
1542 : : /**
1543 : : * fiq_fsm_setup_periodic_dma() - Set up DMA bounce buffers
1544 : : * @hcd: Pointer to the dwc_otg_hcd struct
1545 : : * @qh: Pointer to the endpoint's queue head
1546 : : *
1547 : : * Periodic split transactions are transmitted modulo 188 bytes.
1548 : : * This necessitates slicing data up into buckets for isochronous out
1549 : : * and fixing up the DMA address for all IN transfers.
1550 : : *
1551 : : * Returns 1 if the DMA bounce buffers have been used, 0 if the default
1552 : : * HC buffer has been used.
1553 : : */
1554 : 0 : int fiq_fsm_setup_periodic_dma(dwc_otg_hcd_t *hcd, struct fiq_channel_state *st, dwc_otg_qh_t *qh)
1555 : : {
1556 : : int frame_length, i = 0;
1557 : : uint8_t *ptr = NULL;
1558 : 0 : dwc_hc_t *hc = qh->channel;
1559 : : struct fiq_dma_blob *blob;
1560 : : struct dwc_otg_hcd_iso_packet_desc *frame_desc;
1561 : :
1562 [ # # ]: 0 : for (i = 0; i < 6; i++) {
1563 : 0 : st->dma_info.slot_len[i] = 255;
1564 : : }
1565 : 0 : st->dma_info.index = 0;
1566 : : i = 0;
1567 [ # # ]: 0 : if (hc->ep_is_in) {
1568 : : /*
1569 : : * Set dma_regs to bounce buffer. FIQ will update the
1570 : : * state depending on transaction progress.
1571 : : * Pointer arithmetic on hcd->fiq_state->dma_base (a dma_addr_t)
1572 : : * to point it to the correct offset in the allocated buffers.
1573 : : */
1574 : 0 : blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base;
1575 : 0 : st->hcdma_copy.d32 = (dma_addr_t) blob->channel[hc->hc_num].index[0].buf;
1576 : :
1577 : : /* Calculate the max number of CSPLITS such that the FIQ can time out
1578 : : * a transaction if it fails.
1579 : : */
1580 : 0 : frame_length = st->hcchar_copy.b.mps;
1581 : : do {
1582 : 0 : i++;
1583 : 0 : frame_length -= 188;
1584 [ # # ]: 0 : } while (frame_length >= 0);
1585 : 0 : st->nrpackets = i;
1586 : 0 : return 1;
1587 : : } else {
1588 [ # # ]: 0 : if (qh->ep_type == UE_ISOCHRONOUS) {
1589 : :
1590 : 0 : dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
1591 : :
1592 : 0 : frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
1593 : 0 : frame_length = frame_desc->length;
1594 : :
1595 : : /* Virtual address for bounce buffers */
1596 : 0 : blob = hcd->fiq_dmab;
1597 : :
1598 : 0 : ptr = qtd->urb->buf + frame_desc->offset;
1599 [ # # ]: 0 : if (frame_length == 0) {
1600 : : /*
1601 : : * for isochronous transactions, we must still transmit a packet
1602 : : * even if the length is zero.
1603 : : */
1604 : 0 : st->dma_info.slot_len[0] = 0;
1605 : 0 : st->nrpackets = 1;
1606 : : } else {
1607 : : do {
1608 [ # # ]: 0 : if (frame_length <= 188) {
1609 : 0 : dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length);
1610 : 0 : st->dma_info.slot_len[i] = frame_length;
1611 : 0 : ptr += frame_length;
1612 : : } else {
1613 : 0 : dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188);
1614 : 0 : st->dma_info.slot_len[i] = 188;
1615 : 0 : ptr += 188;
1616 : : }
1617 : 0 : i++;
1618 : 0 : frame_length -= 188;
1619 [ # # ]: 0 : } while (frame_length > 0);
1620 : 0 : st->nrpackets = i;
1621 : : }
1622 : : ptr = qtd->urb->buf + frame_desc->offset;
1623 : : /*
1624 : : * Point the HC at the DMA address of the bounce buffers
1625 : : *
1626 : : * Pointer arithmetic on hcd->fiq_state->dma_base (a
1627 : : * dma_addr_t) to point it to the correct offset in the
1628 : : * allocated buffers.
1629 : : */
1630 : 0 : blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base;
1631 : 0 : st->hcdma_copy.d32 = (dma_addr_t) blob->channel[hc->hc_num].index[0].buf;
1632 : :
1633 : : /* fixup xfersize to the actual packet size */
1634 : 0 : st->hctsiz_copy.b.pid = 0;
1635 : 0 : st->hctsiz_copy.b.xfersize = st->dma_info.slot_len[0];
1636 : 0 : return 1;
1637 : : } else {
1638 : : /* For interrupt, single OUT packet required, goes in the SSPLIT from hc_buff. */
1639 : : return 0;
1640 : : }
1641 : : }
1642 : : }
1643 : :
1644 : : /**
1645 : : * fiq_fsm_np_tt_contended() - Avoid performing contended non-periodic transfers
1646 : : * @hcd: Pointer to the dwc_otg_hcd struct
1647 : : * @qh: Pointer to the endpoint's queue head
1648 : : *
1649 : : * Certain hub chips don't differentiate between IN and OUT non-periodic pipes
1650 : : * with the same endpoint number. If transfers get completed out of order
1651 : : * (disregarding the direction token) then the hub can lock up
1652 : : * or return erroneous responses.
1653 : : *
1654 : : * Returns 1 if initiating the transfer would cause contention, 0 otherwise.
1655 : : */
1656 : 0 : int fiq_fsm_np_tt_contended(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
1657 : : {
1658 : : int i;
1659 : : struct fiq_channel_state *st;
1660 : 0 : int dev_addr = qh->channel->dev_addr;
1661 : 0 : int ep_num = qh->channel->ep_num;
1662 [ # # ]: 0 : for (i = 0; i < hcd->core_if->core_params->host_channels; i++) {
1663 [ # # ]: 0 : if (i == qh->channel->hc_num)
1664 : 0 : continue;
1665 : 0 : st = &hcd->fiq_state->channel[i];
1666 [ # # ]: 0 : switch (st->fsm) {
1667 : : case FIQ_NP_SSPLIT_STARTED:
1668 : : case FIQ_NP_SSPLIT_RETRY:
1669 : : case FIQ_NP_SSPLIT_PENDING:
1670 : : case FIQ_NP_OUT_CSPLIT_RETRY:
1671 : : case FIQ_NP_IN_CSPLIT_RETRY:
1672 [ # # # # ]: 0 : if (st->hcchar_copy.b.devaddr == dev_addr &&
1673 : 0 : st->hcchar_copy.b.epnum == ep_num)
1674 : : return 1;
1675 : : break;
1676 : : default:
1677 : : break;
1678 : : }
1679 : : }
1680 : : return 0;
1681 : : }
1682 : :
1683 : : /*
1684 : : * Pushing a periodic request into the queue near the EOF1 point
1685 : : * in a microframe causes erroneous behaviour (frmovrun) interrupt.
1686 : : * Usually, the request goes out on the bus causing a transfer but
1687 : : * the core does not transfer the data to memory.
1688 : : * This guard interval (in number of 60MHz clocks) is required which
1689 : : * must cater for CPU latency between reading the value and enabling
1690 : : * the channel.
1691 : : */
1692 : : #define PERIODIC_FRREM_BACKOFF 1000
1693 : :
1694 : 0 : int fiq_fsm_queue_isoc_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
1695 : : {
1696 : 0 : dwc_hc_t *hc = qh->channel;
1697 : 0 : dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
1698 : 0 : dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
1699 : : int frame;
1700 : 0 : struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num];
1701 : : int xfer_len, nrpackets;
1702 : : hcdma_data_t hcdma;
1703 : : hfnum_data_t hfnum;
1704 : :
1705 [ # # ]: 0 : if (st->fsm != FIQ_PASSTHROUGH)
1706 : : return 0;
1707 : :
1708 : 0 : st->nr_errors = 0;
1709 : :
1710 : 0 : st->hcchar_copy.d32 = 0;
1711 : 0 : st->hcchar_copy.b.mps = hc->max_packet;
1712 : 0 : st->hcchar_copy.b.epdir = hc->ep_is_in;
1713 : 0 : st->hcchar_copy.b.devaddr = hc->dev_addr;
1714 : 0 : st->hcchar_copy.b.epnum = hc->ep_num;
1715 : 0 : st->hcchar_copy.b.eptype = hc->ep_type;
1716 : :
1717 : 0 : st->hcintmsk_copy.b.chhltd = 1;
1718 : :
1719 : : frame = dwc_otg_hcd_get_frame_number(hcd);
1720 : 0 : st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1;
1721 : :
1722 : 0 : st->hcchar_copy.b.lspddev = 0;
1723 : : /* Enable the channel later as a final register write. */
1724 : :
1725 : 0 : st->hcsplt_copy.d32 = 0;
1726 : :
1727 : 0 : st->hs_isoc_info.iso_desc = (struct dwc_otg_hcd_iso_packet_desc *) &qtd->urb->iso_descs;
1728 : 0 : st->hs_isoc_info.nrframes = qtd->urb->packet_count;
1729 : : /* grab the next DMA address offset from the array */
1730 : 0 : st->hcdma_copy.d32 = qtd->urb->dma;
1731 : 0 : hcdma.d32 = st->hcdma_copy.d32 + st->hs_isoc_info.iso_desc[0].offset;
1732 : :
1733 : : /* We need to set multi_count. This is a bit tricky - has to be set per-transaction as
1734 : : * the core needs to be told to send the correct number. Caution: for IN transfers,
1735 : : * this is always set to the maximum size of the endpoint. */
1736 : 0 : xfer_len = st->hs_isoc_info.iso_desc[0].length;
1737 : 0 : nrpackets = (xfer_len + st->hcchar_copy.b.mps - 1) / st->hcchar_copy.b.mps;
1738 [ # # ]: 0 : if (nrpackets == 0)
1739 : : nrpackets = 1;
1740 : 0 : st->hcchar_copy.b.multicnt = nrpackets;
1741 : 0 : st->hctsiz_copy.b.pktcnt = nrpackets;
1742 : :
1743 : : /* Initial PID also needs to be set */
1744 [ # # ]: 0 : if (st->hcchar_copy.b.epdir == 0) {
1745 : 0 : st->hctsiz_copy.b.xfersize = xfer_len;
1746 [ # # # ]: 0 : switch (st->hcchar_copy.b.multicnt) {
1747 : : case 1:
1748 : 0 : st->hctsiz_copy.b.pid = DWC_PID_DATA0;
1749 : 0 : break;
1750 : : case 2:
1751 : : case 3:
1752 : 0 : st->hctsiz_copy.b.pid = DWC_PID_MDATA;
1753 : 0 : break;
1754 : : }
1755 : :
1756 : : } else {
1757 : 0 : st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps;
1758 [ # # # # ]: 0 : switch (st->hcchar_copy.b.multicnt) {
1759 : : case 1:
1760 : 0 : st->hctsiz_copy.b.pid = DWC_PID_DATA0;
1761 : 0 : break;
1762 : : case 2:
1763 : 0 : st->hctsiz_copy.b.pid = DWC_PID_DATA1;
1764 : 0 : break;
1765 : : case 3:
1766 : 0 : st->hctsiz_copy.b.pid = DWC_PID_DATA2;
1767 : 0 : break;
1768 : : }
1769 : : }
1770 : :
1771 : 0 : st->hs_isoc_info.stride = qh->interval;
1772 : 0 : st->uframe_sleeps = 0;
1773 : :
1774 : : fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d ", hc->hc_num);
1775 : : fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcchar_copy.d32);
1776 : : fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32);
1777 : : fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32);
1778 : 0 : hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
1779 : 0 : local_fiq_disable();
1780 : 0 : fiq_fsm_spin_lock(&hcd->fiq_state->lock);
1781 : 0 : DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32);
1782 : 0 : DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32);
1783 : 0 : DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32);
1784 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32);
1785 : 0 : DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32);
1786 [ # # ]: 0 : if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) {
1787 : : /* Prevent queueing near EOF1. Bad things happen if a periodic
1788 : : * split transaction is queued very close to EOF. SOF interrupt handler
1789 : : * will wake this channel at the next interrupt.
1790 : : */
1791 : 0 : st->fsm = FIQ_HS_ISOC_SLEEPING;
1792 : 0 : st->uframe_sleeps = 1;
1793 : : } else {
1794 : 0 : st->fsm = FIQ_HS_ISOC_TURBO;
1795 : 0 : st->hcchar_copy.b.chen = 1;
1796 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32);
1797 : : }
1798 : 0 : mb();
1799 : 0 : st->hcchar_copy.b.chen = 0;
1800 : 0 : fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
1801 : 0 : local_fiq_enable();
1802 : 0 : return 0;
1803 : : }
1804 : :
1805 : :
1806 : : /**
1807 : : * fiq_fsm_queue_split_transaction() - Set up a host channel and FIQ state
1808 : : * @hcd: Pointer to the dwc_otg_hcd struct
1809 : : * @qh: Pointer to the endpoint's queue head
1810 : : *
1811 : : * This overrides the dwc_otg driver's normal method of queueing a transaction.
1812 : : * Called from dwc_otg_hcd_queue_transactions(), this performs specific setup
1813 : : * for the nominated host channel.
1814 : : *
1815 : : * For periodic transfers, it also peeks at the FIQ state to see if an immediate
1816 : : * start is possible. If not, then the FIQ is left to start the transfer.
1817 : : */
1818 : 0 : int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
1819 : : {
1820 : : int start_immediate = 1, i;
1821 : : hfnum_data_t hfnum;
1822 : 0 : dwc_hc_t *hc = qh->channel;
1823 : 0 : dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
1824 : : /* Program HC registers, setup FIQ_state, examine FIQ if periodic, start transfer (not if uframe 5) */
1825 : : int hub_addr, port_addr, frame, uframe;
1826 : 0 : struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num];
1827 : :
1828 : : /*
1829 : : * Non-periodic channel assignments stay in the non_periodic_active queue.
1830 : : * Therefore we get repeatedly called until the FIQ's done processing this channel.
1831 : : */
1832 [ # # ]: 0 : if (qh->channel->xfer_started == 1)
1833 : : return 0;
1834 : :
1835 [ # # ]: 0 : if (st->fsm != FIQ_PASSTHROUGH) {
1836 [ # # ]: 0 : pr_warn_ratelimited("%s:%d: Queue called for an active channel\n", __func__, __LINE__);
1837 : : return 0;
1838 : : }
1839 : :
1840 : 0 : qh->channel->xfer_started = 1;
1841 : :
1842 : 0 : st->nr_errors = 0;
1843 : :
1844 : 0 : st->hcchar_copy.d32 = 0;
1845 : 0 : st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet);
1846 : 0 : st->hcchar_copy.b.epdir = hc->ep_is_in;
1847 : 0 : st->hcchar_copy.b.devaddr = hc->dev_addr;
1848 : 0 : st->hcchar_copy.b.epnum = hc->ep_num;
1849 : 0 : st->hcchar_copy.b.eptype = hc->ep_type;
1850 [ # # ]: 0 : if (hc->ep_type & 0x1) {
1851 [ # # ]: 0 : if (hc->ep_is_in)
1852 : 0 : st->hcchar_copy.b.multicnt = 3;
1853 : : else
1854 : : /* Docs say set this to 1, but driver sets to 0! */
1855 : 0 : st->hcchar_copy.b.multicnt = 0;
1856 : : } else {
1857 : 0 : st->hcchar_copy.b.multicnt = 1;
1858 : 0 : st->hcchar_copy.b.oddfrm = 0;
1859 : : }
1860 : 0 : st->hcchar_copy.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW) ? 1 : 0;
1861 : : /* Enable the channel later as a final register write. */
1862 : :
1863 : 0 : st->hcsplt_copy.d32 = 0;
1864 [ # # ]: 0 : if(qh->do_split) {
1865 : 0 : hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr);
1866 : 0 : st->hcsplt_copy.b.compsplt = 0;
1867 : 0 : st->hcsplt_copy.b.spltena = 1;
1868 : : // XACTPOS is for isoc-out only but needs initialising anyway.
1869 : 0 : st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_ALL;
1870 [ # # ]: 0 : if((qh->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!qh->ep_is_in)) {
1871 : : /* For packetsize 0 < L < 188, ISOC_XACTPOS_ALL.
1872 : : * for longer than this, ISOC_XACTPOS_BEGIN and the FIQ
1873 : : * will update as necessary.
1874 : : */
1875 [ # # ]: 0 : if (hc->xfer_len > 188) {
1876 : 0 : st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_BEGIN;
1877 : : }
1878 : : }
1879 : 0 : st->hcsplt_copy.b.hubaddr = (uint8_t) hub_addr;
1880 : 0 : st->hcsplt_copy.b.prtaddr = (uint8_t) port_addr;
1881 : 0 : st->hub_addr = hub_addr;
1882 : 0 : st->port_addr = port_addr;
1883 : : }
1884 : :
1885 : 0 : st->hctsiz_copy.d32 = 0;
1886 : 0 : st->hctsiz_copy.b.dopng = 0;
1887 : 0 : st->hctsiz_copy.b.pid = hc->data_pid_start;
1888 : :
1889 [ # # # # ]: 0 : if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
1890 : 0 : hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet);
1891 [ # # # # ]: 0 : } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
1892 : 0 : hc->xfer_len = 188;
1893 : : }
1894 : 0 : st->hctsiz_copy.b.xfersize = hc->xfer_len;
1895 : :
1896 : 0 : st->hctsiz_copy.b.pktcnt = 1;
1897 : :
1898 [ # # ]: 0 : if (hc->ep_type & 0x1) {
1899 : : /*
1900 : : * For potentially multi-packet transfers, must use the DMA bounce buffers. For IN transfers,
1901 : : * the DMA address is the address of the first 188byte slot buffer in the bounce buffer array.
1902 : : * For multi-packet OUT transfers, we need to copy the data into the bounce buffer array so the FIQ can punt
1903 : : * the right address out as necessary. hc->xfer_buff and hc->xfer_len have already been set
1904 : : * in assign_and_init_hc(), but this is for the eventual transaction completion only. The FIQ
1905 : : * must not touch internal driver state.
1906 : : */
1907 [ # # ]: 0 : if(!fiq_fsm_setup_periodic_dma(hcd, st, qh)) {
1908 [ # # ]: 0 : if (hc->align_buff) {
1909 : 0 : st->hcdma_copy.d32 = hc->align_buff;
1910 : : } else {
1911 : 0 : st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
1912 : : }
1913 : : }
1914 : : } else {
1915 [ # # ]: 0 : if (hc->align_buff) {
1916 : 0 : st->hcdma_copy.d32 = hc->align_buff;
1917 : : } else {
1918 : 0 : st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
1919 : : }
1920 : : }
1921 : : /* The FIQ depends upon no other interrupts being enabled except channel halt.
1922 : : * Fixup channel interrupt mask. */
1923 : 0 : st->hcintmsk_copy.d32 = 0;
1924 : 0 : st->hcintmsk_copy.b.chhltd = 1;
1925 : 0 : st->hcintmsk_copy.b.ahberr = 1;
1926 : :
1927 : : /* Hack courtesy of FreeBSD: apparently forcing Interrupt Split transactions
1928 : : * as Control puts the transfer into the non-periodic request queue and the
1929 : : * non-periodic handler in the hub. Makes things lots easier.
1930 : : */
1931 [ # # # # ]: 0 : if ((fiq_fsm_mask & 0x8) && hc->ep_type == UE_INTERRUPT) {
1932 : 0 : st->hcchar_copy.b.multicnt = 0;
1933 : 0 : st->hcchar_copy.b.oddfrm = 0;
1934 : 0 : st->hcchar_copy.b.eptype = UE_CONTROL;
1935 [ # # ]: 0 : if (hc->align_buff) {
1936 : 0 : st->hcdma_copy.d32 = hc->align_buff;
1937 : : } else {
1938 : 0 : st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF);
1939 : : }
1940 : : }
1941 : 0 : DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32);
1942 : 0 : DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32);
1943 : 0 : DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32);
1944 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32);
1945 : 0 : DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32);
1946 : :
1947 : 0 : local_fiq_disable();
1948 : 0 : fiq_fsm_spin_lock(&hcd->fiq_state->lock);
1949 : :
1950 [ # # ]: 0 : if (hc->ep_type & 0x1) {
1951 : 0 : hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
1952 : : frame = (hfnum.b.frnum & ~0x7) >> 3;
1953 : 0 : uframe = hfnum.b.frnum & 0x7;
1954 [ # # ]: 0 : if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) {
1955 : : /* Prevent queueing near EOF1. Bad things happen if a periodic
1956 : : * split transaction is queued very close to EOF.
1957 : : */
1958 : : start_immediate = 0;
1959 [ # # ]: 0 : } else if (uframe == 5) {
1960 : : start_immediate = 0;
1961 [ # # ]: 0 : } else if (hc->ep_type == UE_ISOCHRONOUS && !hc->ep_is_in) {
1962 : : start_immediate = 0;
1963 [ # # # # ]: 0 : } else if (hc->ep_is_in && fiq_fsm_too_late(hcd->fiq_state, hc->hc_num)) {
1964 : : start_immediate = 0;
1965 : : } else {
1966 : : /* Search through all host channels to determine if a transaction
1967 : : * is currently in progress */
1968 [ # # ]: 0 : for (i = 0; i < hcd->core_if->core_params->host_channels; i++) {
1969 [ # # # # ]: 0 : if (i == hc->hc_num || hcd->fiq_state->channel[i].fsm == FIQ_PASSTHROUGH)
1970 : 0 : continue;
1971 [ # # ]: 0 : switch (hcd->fiq_state->channel[i].fsm) {
1972 : : /* TT is reserved for channels that are in the middle of a periodic
1973 : : * split transaction.
1974 : : */
1975 : : case FIQ_PER_SSPLIT_STARTED:
1976 : : case FIQ_PER_CSPLIT_WAIT:
1977 : : case FIQ_PER_CSPLIT_NYET1:
1978 : : case FIQ_PER_CSPLIT_POLL:
1979 : : case FIQ_PER_ISO_OUT_ACTIVE:
1980 : : case FIQ_PER_ISO_OUT_LAST:
1981 [ # # # # ]: 0 : if (hcd->fiq_state->channel[i].hub_addr == hub_addr &&
1982 : 0 : hcd->fiq_state->channel[i].port_addr == port_addr) {
1983 : : start_immediate = 0;
1984 : : }
1985 : : break;
1986 : : default:
1987 : : break;
1988 : : }
1989 [ # # ]: 0 : if (!start_immediate)
1990 : : break;
1991 : : }
1992 : : }
1993 : : }
1994 [ # # # # ]: 0 : if ((fiq_fsm_mask & 0x8) && hc->ep_type == UE_INTERRUPT)
1995 : : start_immediate = 1;
1996 : :
1997 : : fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d %01d", hc->hc_num, start_immediate);
1998 : : fiq_print(FIQDBG_INT, hcd->fiq_state, "%08d", hfnum.b.frrem);
1999 : : //fiq_print(FIQDBG_INT, hcd->fiq_state, "H:%02dP:%02d", hub_addr, port_addr);
2000 : : //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32);
2001 : : //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32);
2002 [ # # # # ]: 0 : switch (hc->ep_type) {
2003 : : case UE_CONTROL:
2004 : : case UE_BULK:
2005 [ # # ]: 0 : if (fiq_fsm_np_tt_contended(hcd, qh)) {
2006 : 0 : st->fsm = FIQ_NP_SSPLIT_PENDING;
2007 : : start_immediate = 0;
2008 : : } else {
2009 : 0 : st->fsm = FIQ_NP_SSPLIT_STARTED;
2010 : : }
2011 : : break;
2012 : : case UE_ISOCHRONOUS:
2013 [ # # ]: 0 : if (hc->ep_is_in) {
2014 [ # # ]: 0 : if (start_immediate) {
2015 : 0 : st->fsm = FIQ_PER_SSPLIT_STARTED;
2016 : : } else {
2017 : 0 : st->fsm = FIQ_PER_SSPLIT_QUEUED;
2018 : : }
2019 : : } else {
2020 [ # # ]: 0 : if (start_immediate) {
2021 : : /* Single-isoc OUT packets don't require FIQ involvement */
2022 [ # # ]: 0 : if (st->nrpackets == 1) {
2023 : 0 : st->fsm = FIQ_PER_ISO_OUT_LAST;
2024 : : } else {
2025 : 0 : st->fsm = FIQ_PER_ISO_OUT_ACTIVE;
2026 : : }
2027 : : } else {
2028 : 0 : st->fsm = FIQ_PER_ISO_OUT_PENDING;
2029 : : }
2030 : : }
2031 : : break;
2032 : : case UE_INTERRUPT:
2033 [ # # ]: 0 : if (fiq_fsm_mask & 0x8) {
2034 [ # # ]: 0 : if (fiq_fsm_np_tt_contended(hcd, qh)) {
2035 : 0 : st->fsm = FIQ_NP_SSPLIT_PENDING;
2036 : : start_immediate = 0;
2037 : : } else {
2038 : 0 : st->fsm = FIQ_NP_SSPLIT_STARTED;
2039 : : }
2040 [ # # ]: 0 : } else if (start_immediate) {
2041 : 0 : st->fsm = FIQ_PER_SSPLIT_STARTED;
2042 : : } else {
2043 : 0 : st->fsm = FIQ_PER_SSPLIT_QUEUED;
2044 : : }
2045 : : default:
2046 : : break;
2047 : : }
2048 [ # # ]: 0 : if (start_immediate) {
2049 : : /* Set the oddfrm bit as close as possible to actual queueing */
2050 : : frame = dwc_otg_hcd_get_frame_number(hcd);
2051 : 0 : st->expected_uframe = (frame + 1) & 0x3FFF;
2052 : 0 : st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1;
2053 : 0 : st->hcchar_copy.b.chen = 1;
2054 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32);
2055 : : }
2056 : 0 : mb();
2057 : 0 : fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
2058 : 0 : local_fiq_enable();
2059 : 0 : return 0;
2060 : : }
2061 : :
2062 : :
2063 : : /**
2064 : : * This function selects transactions from the HCD transfer schedule and
2065 : : * assigns them to available host channels. It is called from HCD interrupt
2066 : : * handler functions.
2067 : : *
2068 : : * @param hcd The HCD state structure.
2069 : : *
2070 : : * @return The types of new transactions that were assigned to host channels.
2071 : : */
2072 : 276240786 : dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
2073 : : {
2074 : : dwc_list_link_t *qh_ptr;
2075 : : dwc_otg_qh_t *qh;
2076 : : int num_channels;
2077 : : dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
2078 : :
2079 : : #ifdef DEBUG_HOST_CHANNELS
2080 : : last_sel_trans_num_per_scheduled = 0;
2081 : : last_sel_trans_num_nonper_scheduled = 0;
2082 : : last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
2083 : : #endif /* DEBUG_HOST_CHANNELS */
2084 : :
2085 : : /* Process entries in the periodic ready list. */
2086 : 276240786 : qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
2087 : :
2088 [ + + + - ]: 1007521188 : while (qh_ptr != &hcd->periodic_sched_ready &&
2089 : 227519814 : !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
2090 : :
2091 : : qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
2092 : :
2093 [ + - ]: 227519814 : if (microframe_schedule) {
2094 : : // Make sure we leave one channel for non periodic transactions.
2095 [ + - ]: 227519814 : if (hcd->available_host_channels <= 1) {
2096 : : break;
2097 : : }
2098 : 227519814 : hcd->available_host_channels--;
2099 : : #ifdef DEBUG_HOST_CHANNELS
2100 : : last_sel_trans_num_per_scheduled++;
2101 : : #endif /* DEBUG_HOST_CHANNELS */
2102 : : }
2103 : 227519814 : qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
2104 : 227519814 : assign_and_init_hc(hcd, qh);
2105 : :
2106 : : /*
2107 : : * Move the QH from the periodic ready schedule to the
2108 : : * periodic assigned schedule.
2109 : : */
2110 : 227519802 : qh_ptr = DWC_LIST_NEXT(qh_ptr);
2111 : 227519802 : DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
2112 : : &qh->qh_list_entry);
2113 : : }
2114 : :
2115 : : /*
2116 : : * Process entries in the inactive portion of the non-periodic
2117 : : * schedule. Some free host channels may not be used if they are
2118 : : * reserved for periodic transfers.
2119 : : */
2120 : 276240774 : qh_ptr = hcd->non_periodic_sched_inactive.next;
2121 : 276240774 : num_channels = hcd->core_if->core_params->host_channels;
2122 [ + + - + ]: 552783340 : while (qh_ptr != &hcd->non_periodic_sched_inactive &&
2123 [ # # ]: 150896 : (microframe_schedule || hcd->non_periodic_channels <
2124 [ + - ]: 150896 : num_channels - hcd->periodic_channels) &&
2125 : 150896 : !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
2126 : :
2127 : 150896 : qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
2128 : : /*
2129 : : * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission
2130 : : * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed
2131 : : * cheeky devices that just hold off using NAKs
2132 : : */
2133 [ + - + - : 150896 : if (fiq_enable && nak_holdoff && qh->do_split) {
- + ]
2134 [ # # ]: 0 : if (qh->nak_frame != 0xffff) {
2135 [ # # ]: 0 : uint16_t next_frame = dwc_frame_num_inc(qh->nak_frame, (qh->ep_type == UE_BULK) ? nak_holdoff : 8);
2136 : : uint16_t frame = dwc_otg_hcd_get_frame_number(hcd);
2137 [ # # ]: 0 : if (dwc_frame_num_le(frame, next_frame)) {
2138 [ # # ]: 0 : if(dwc_frame_num_le(next_frame, hcd->fiq_state->next_sched_frame)) {
2139 : 0 : hcd->fiq_state->next_sched_frame = next_frame;
2140 : : }
2141 : 0 : qh_ptr = DWC_LIST_NEXT(qh_ptr);
2142 : 0 : continue;
2143 : : } else {
2144 : 0 : qh->nak_frame = 0xFFFF;
2145 : : }
2146 : : }
2147 : : }
2148 : :
2149 [ + - ]: 150896 : if (microframe_schedule) {
2150 [ + - ]: 150896 : if (hcd->available_host_channels < 1) {
2151 : : break;
2152 : : }
2153 : 150896 : hcd->available_host_channels--;
2154 : : #ifdef DEBUG_HOST_CHANNELS
2155 : : last_sel_trans_num_nonper_scheduled++;
2156 : : #endif /* DEBUG_HOST_CHANNELS */
2157 : : }
2158 : :
2159 : 150896 : assign_and_init_hc(hcd, qh);
2160 : :
2161 : : /*
2162 : : * Move the QH from the non-periodic inactive schedule to the
2163 : : * non-periodic active schedule.
2164 : : */
2165 : 150896 : qh_ptr = DWC_LIST_NEXT(qh_ptr);
2166 : 150896 : DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
2167 : : &qh->qh_list_entry);
2168 : :
2169 [ - + ]: 150896 : if (!microframe_schedule)
2170 : 0 : hcd->non_periodic_channels++;
2171 : : }
2172 : : /* we moved a non-periodic QH to the active schedule. If the inactive queue is empty,
2173 : : * stop the FIQ from kicking us. We could potentially still have elements here if we
2174 : : * ran out of host channels.
2175 : : */
2176 [ + - ]: 276240774 : if (fiq_enable) {
2177 [ + - ]: 276240774 : if (DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) {
2178 : 276240774 : hcd->fiq_state->kick_np_queues = 0;
2179 : : } else {
2180 : : /* For each entry remaining in the NP inactive queue,
2181 : : * if this a NAK'd retransmit then don't set the kick flag.
2182 : : */
2183 [ # # ]: 0 : if(nak_holdoff) {
2184 [ # # ]: 0 : DWC_LIST_FOREACH(qh_ptr, &hcd->non_periodic_sched_inactive) {
2185 : : qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
2186 [ # # ]: 0 : if (qh->nak_frame == 0xFFFF) {
2187 : 0 : hcd->fiq_state->kick_np_queues = 1;
2188 : : }
2189 : : }
2190 : : }
2191 : : }
2192 : : }
2193 [ + + ]: 276240774 : if(!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned))
2194 : : ret_val |= DWC_OTG_TRANSACTION_PERIODIC;
2195 : :
2196 [ + + ]: 276240774 : if(!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active))
2197 : 220709810 : ret_val |= DWC_OTG_TRANSACTION_NON_PERIODIC;
2198 : :
2199 : :
2200 : : #ifdef DEBUG_HOST_CHANNELS
2201 : : last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
2202 : : #endif /* DEBUG_HOST_CHANNELS */
2203 : 276240774 : return ret_val;
2204 : : }
2205 : :
2206 : : /**
2207 : : * Attempts to queue a single transaction request for a host channel
2208 : : * associated with either a periodic or non-periodic transfer. This function
2209 : : * assumes that there is space available in the appropriate request queue. For
2210 : : * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
2211 : : * is available in the appropriate Tx FIFO.
2212 : : *
2213 : : * @param hcd The HCD state structure.
2214 : : * @param hc Host channel descriptor associated with either a periodic or
2215 : : * non-periodic transfer.
2216 : : * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
2217 : : * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
2218 : : * transfers.
2219 : : *
2220 : : * @return 1 if a request is queued and more requests may be needed to
2221 : : * complete the transfer, 0 if no more requests are required for this
2222 : : * transfer, -1 if there is insufficient space in the Tx FIFO.
2223 : : */
2224 : 448283884 : static int queue_transaction(dwc_otg_hcd_t * hcd,
2225 : : dwc_hc_t * hc, uint16_t fifo_dwords_avail)
2226 : : {
2227 : : int retval;
2228 : :
2229 [ + - ]: 448283884 : if (hcd->core_if->dma_enable) {
2230 [ - + ]: 448283884 : if (hcd->core_if->dma_desc_enable) {
2231 [ # # ]: 0 : if (!hc->xfer_started
2232 [ # # ]: 0 : || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
2233 : 0 : dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
2234 : 0 : hc->qh->ping_state = 0;
2235 : : }
2236 [ + + ]: 448283884 : } else if (!hc->xfer_started) {
2237 [ - + # # ]: 227670648 : if (fiq_fsm_enable && hc->error_state) {
2238 : 0 : hcd->fiq_state->channel[hc->hc_num].nr_errors =
2239 : 0 : DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list)->error_count;
2240 : 0 : hcd->fiq_state->channel[hc->hc_num].fsm =
2241 : : FIQ_PASSTHROUGH_ERRORSTATE;
2242 : : }
2243 : 227670648 : dwc_otg_hc_start_transfer(hcd->core_if, hc);
2244 : 227670634 : hc->qh->ping_state = 0;
2245 : : }
2246 : : retval = 0;
2247 [ # # ]: 0 : } else if (hc->halt_pending) {
2248 : : /* Don't queue a request if the channel has been halted. */
2249 : : retval = 0;
2250 [ # # ]: 0 : } else if (hc->halt_on_queue) {
2251 : 0 : dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
2252 : : retval = 0;
2253 [ # # ]: 0 : } else if (hc->do_ping) {
2254 [ # # ]: 0 : if (!hc->xfer_started) {
2255 : 0 : dwc_otg_hc_start_transfer(hcd->core_if, hc);
2256 : : }
2257 : : retval = 0;
2258 [ # # # # ]: 0 : } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
2259 [ # # ]: 0 : if ((fifo_dwords_avail * 4) >= hc->max_packet) {
2260 [ # # ]: 0 : if (!hc->xfer_started) {
2261 : 0 : dwc_otg_hc_start_transfer(hcd->core_if, hc);
2262 : : retval = 1;
2263 : : } else {
2264 : 0 : retval =
2265 : : dwc_otg_hc_continue_transfer(hcd->core_if,
2266 : : hc);
2267 : : }
2268 : : } else {
2269 : : retval = -1;
2270 : : }
2271 : : } else {
2272 [ # # ]: 0 : if (!hc->xfer_started) {
2273 : 0 : dwc_otg_hc_start_transfer(hcd->core_if, hc);
2274 : : retval = 1;
2275 : : } else {
2276 : 0 : retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
2277 : : }
2278 : : }
2279 : :
2280 : 448283870 : return retval;
2281 : : }
2282 : :
2283 : : /**
2284 : : * Processes periodic channels for the next frame and queues transactions for
2285 : : * these channels to the DWC_otg controller. After queueing transactions, the
2286 : : * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
2287 : : * to queue as Periodic Tx FIFO or request queue space becomes available.
2288 : : * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
2289 : : */
2290 : 151261782 : static void process_periodic_channels(dwc_otg_hcd_t * hcd)
2291 : : {
2292 : : hptxsts_data_t tx_status;
2293 : : dwc_list_link_t *qh_ptr;
2294 : : dwc_otg_qh_t *qh;
2295 : : int status = 0;
2296 : : int no_queue_space = 0;
2297 : : int no_fifo_space = 0;
2298 : :
2299 : : dwc_otg_host_global_regs_t *host_regs;
2300 : 151261782 : host_regs = hcd->core_if->host_if->host_global_regs;
2301 : :
2302 : : DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
2303 : : #ifdef DEBUG
2304 : : tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
2305 : : DWC_DEBUGPL(DBG_HCDV,
2306 : : " P Tx Req Queue Space Avail (before queue): %d\n",
2307 : : tx_status.b.ptxqspcavail);
2308 : : DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
2309 : : tx_status.b.ptxfspcavail);
2310 : : #endif
2311 : :
2312 : 151261782 : qh_ptr = hcd->periodic_sched_assigned.next;
2313 [ + + ]: 530043270 : while (qh_ptr != &hcd->periodic_sched_assigned) {
2314 : 227519716 : tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
2315 [ + - ]: 227519714 : if (tx_status.b.ptxqspcavail == 0) {
2316 : : no_queue_space = 1;
2317 : : break;
2318 : : }
2319 : :
2320 : 227519714 : qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
2321 : :
2322 : : // Do not send a split start transaction any later than frame .6
2323 : : // Note, we have to schedule a periodic in .5 to make it go in .6
2324 [ - + # # : 227519714 : if(fiq_fsm_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6)
# # ]
2325 : : {
2326 : 0 : qh_ptr = qh_ptr->next;
2327 : 0 : hcd->fiq_state->next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7;
2328 : 0 : continue;
2329 : : }
2330 : :
2331 [ - + # # ]: 227519714 : if (fiq_fsm_enable && fiq_fsm_transaction_suitable(hcd, qh)) {
2332 [ # # ]: 0 : if (qh->do_split)
2333 : 0 : fiq_fsm_queue_split_transaction(hcd, qh);
2334 : : else
2335 : 0 : fiq_fsm_queue_isoc_transaction(hcd, qh);
2336 : : } else {
2337 : :
2338 : : /*
2339 : : * Set a flag if we're queueing high-bandwidth in slave mode.
2340 : : * The flag prevents any halts to get into the request queue in
2341 : : * the middle of multiple high-bandwidth packets getting queued.
2342 : : */
2343 [ - + # # ]: 227519714 : if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
2344 : 0 : hcd->core_if->queuing_high_bandwidth = 1;
2345 : : }
2346 : 227519714 : status = queue_transaction(hcd, qh->channel,
2347 : : tx_status.b.ptxfspcavail);
2348 [ + - ]: 227519706 : if (status < 0) {
2349 : : no_fifo_space = 1;
2350 : : break;
2351 : : }
2352 : : }
2353 : :
2354 : : /*
2355 : : * In Slave mode, stay on the current transfer until there is
2356 : : * nothing more to do or the high-bandwidth request count is
2357 : : * reached. In DMA mode, only need to queue one request. The
2358 : : * controller automatically handles multiple packets for
2359 : : * high-bandwidth transfers.
2360 : : */
2361 [ - + # # : 227519706 : if (hcd->core_if->dma_enable || status == 0 ||
# # ]
2362 : 0 : qh->channel->requests == qh->channel->multi_count) {
2363 : 227519706 : qh_ptr = qh_ptr->next;
2364 : : /*
2365 : : * Move the QH from the periodic assigned schedule to
2366 : : * the periodic queued schedule.
2367 : : */
2368 : 227519706 : DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
2369 : : &qh->qh_list_entry);
2370 : :
2371 : : /* done queuing high bandwidth */
2372 : 227519706 : hcd->core_if->queuing_high_bandwidth = 0;
2373 : : }
2374 : : }
2375 : :
2376 [ - + ]: 151261772 : if (!hcd->core_if->dma_enable) {
2377 : : dwc_otg_core_global_regs_t *global_regs;
2378 : 0 : gintmsk_data_t intr_mask = {.d32 = 0 };
2379 : :
2380 : 0 : global_regs = hcd->core_if->core_global_regs;
2381 : 0 : intr_mask.b.ptxfempty = 1;
2382 : : #ifdef DEBUG
2383 : : tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
2384 : : DWC_DEBUGPL(DBG_HCDV,
2385 : : " P Tx Req Queue Space Avail (after queue): %d\n",
2386 : : tx_status.b.ptxqspcavail);
2387 : : DWC_DEBUGPL(DBG_HCDV,
2388 : : " P Tx FIFO Space Avail (after queue): %d\n",
2389 : : tx_status.b.ptxfspcavail);
2390 : : #endif
2391 [ # # ]: 0 : if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
2392 [ # # ]: 0 : no_queue_space || no_fifo_space) {
2393 : : /*
2394 : : * May need to queue more transactions as the request
2395 : : * queue or Tx FIFO empties. Enable the periodic Tx
2396 : : * FIFO empty interrupt. (Always use the half-empty
2397 : : * level to ensure that new requests are loaded as
2398 : : * soon as possible.)
2399 : : */
2400 : 0 : DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
2401 : : intr_mask.d32);
2402 : : } else {
2403 : : /*
2404 : : * Disable the Tx FIFO empty interrupt since there are
2405 : : * no more transactions that need to be queued right
2406 : : * now. This function is called from interrupt
2407 : : * handlers to queue more transactions as transfer
2408 : : * states change.
2409 : : */
2410 : 0 : DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
2411 : : 0);
2412 : : }
2413 : : }
2414 : 151261772 : }
2415 : :
2416 : : /**
2417 : : * Processes active non-periodic channels and queues transactions for these
2418 : : * channels to the DWC_otg controller. After queueing transactions, the NP Tx
2419 : : * FIFO Empty interrupt is enabled if there are more transactions to queue as
2420 : : * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
2421 : : * FIFO Empty interrupt is disabled.
2422 : : */
2423 : 220709690 : static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
2424 : : {
2425 : : gnptxsts_data_t tx_status;
2426 : : dwc_list_link_t *orig_qh_ptr;
2427 : : dwc_otg_qh_t *qh;
2428 : : int status;
2429 : : int no_queue_space = 0;
2430 : : int no_fifo_space = 0;
2431 : : int more_to_do = 0;
2432 : :
2433 : 220709690 : dwc_otg_core_global_regs_t *global_regs =
2434 : 220709690 : hcd->core_if->core_global_regs;
2435 : :
2436 : : DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
2437 : : #ifdef DEBUG
2438 : : tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
2439 : : DWC_DEBUGPL(DBG_HCDV,
2440 : : " NP Tx Req Queue Space Avail (before queue): %d\n",
2441 : : tx_status.b.nptxqspcavail);
2442 : : DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
2443 : : tx_status.b.nptxfspcavail);
2444 : : #endif
2445 : : /*
2446 : : * Keep track of the starting point. Skip over the start-of-list
2447 : : * entry.
2448 : : */
2449 [ + + ]: 220709690 : if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
2450 : 127670 : hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
2451 : : }
2452 : 220709690 : orig_qh_ptr = hcd->non_periodic_qh_ptr;
2453 : :
2454 : : /*
2455 : : * Process once through the active list or until no more space is
2456 : : * available in the request queue or the Tx FIFO.
2457 : : */
2458 : : do {
2459 : 220764068 : tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
2460 [ - + # # ]: 220764066 : if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
2461 : : no_queue_space = 1;
2462 : : break;
2463 : : }
2464 : :
2465 : 220764066 : qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
2466 : : qh_list_entry);
2467 : :
2468 [ - + # # ]: 220764066 : if(fiq_fsm_enable && fiq_fsm_transaction_suitable(hcd, qh)) {
2469 : 0 : fiq_fsm_queue_split_transaction(hcd, qh);
2470 : : } else {
2471 : 220764066 : status = queue_transaction(hcd, qh->channel,
2472 : : tx_status.b.nptxfspcavail);
2473 : :
2474 [ + - ]: 220764066 : if (status > 0) {
2475 : : more_to_do = 1;
2476 [ + - ]: 220764066 : } else if (status < 0) {
2477 : : no_fifo_space = 1;
2478 : : break;
2479 : : }
2480 : : }
2481 : : /* Advance to next QH, skipping start-of-list entry. */
2482 : 220764066 : hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
2483 [ + + ]: 220764066 : if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
2484 : 220709688 : hcd->non_periodic_qh_ptr =
2485 : 220709688 : hcd->non_periodic_qh_ptr->next;
2486 : : }
2487 : :
2488 [ + + ]: 220764066 : } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
2489 : :
2490 [ - + ]: 220709688 : if (!hcd->core_if->dma_enable) {
2491 : 0 : gintmsk_data_t intr_mask = {.d32 = 0 };
2492 : 0 : intr_mask.b.nptxfempty = 1;
2493 : :
2494 : : #ifdef DEBUG
2495 : : tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
2496 : : DWC_DEBUGPL(DBG_HCDV,
2497 : : " NP Tx Req Queue Space Avail (after queue): %d\n",
2498 : : tx_status.b.nptxqspcavail);
2499 : : DWC_DEBUGPL(DBG_HCDV,
2500 : : " NP Tx FIFO Space Avail (after queue): %d\n",
2501 : : tx_status.b.nptxfspcavail);
2502 : : #endif
2503 [ # # ]: 0 : if (more_to_do || no_queue_space || no_fifo_space) {
2504 : : /*
2505 : : * May need to queue more transactions as the request
2506 : : * queue or Tx FIFO empties. Enable the non-periodic
2507 : : * Tx FIFO empty interrupt. (Always use the half-empty
2508 : : * level to ensure that new requests are loaded as
2509 : : * soon as possible.)
2510 : : */
2511 : 0 : DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
2512 : : intr_mask.d32);
2513 : : } else {
2514 : : /*
2515 : : * Disable the Tx FIFO empty interrupt since there are
2516 : : * no more transactions that need to be queued right
2517 : : * now. This function is called from interrupt
2518 : : * handlers to queue more transactions as transfer
2519 : : * states change.
2520 : : */
2521 : 0 : DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
2522 : : 0);
2523 : : }
2524 : : }
2525 : 220709688 : }
2526 : :
2527 : : /**
2528 : : * This function processes the currently active host channels and queues
2529 : : * transactions for these channels to the DWC_otg controller. It is called
2530 : : * from HCD interrupt handler functions.
2531 : : *
2532 : : * @param hcd The HCD state structure.
2533 : : * @param tr_type The type(s) of transactions to queue (non-periodic,
2534 : : * periodic, or both).
2535 : : */
2536 : 254428344 : void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
2537 : : dwc_otg_transaction_type_e tr_type)
2538 : : {
2539 : : #ifdef DEBUG_SOF
2540 : : DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
2541 : : #endif
2542 : : /* Process host channels associated with periodic transfers. */
2543 [ + + ]: 508856688 : if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
2544 [ + - ]: 405690096 : tr_type == DWC_OTG_TRANSACTION_ALL) &&
2545 : 151261752 : !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
2546 : :
2547 : 151261752 : process_periodic_channels(hcd);
2548 : : }
2549 : :
2550 : : /* Process host channels associated with non-periodic transfers. */
2551 [ + + ]: 254428328 : if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
2552 : : tr_type == DWC_OTG_TRANSACTION_ALL) {
2553 [ + - ]: 220709662 : if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
2554 : 220709662 : process_non_periodic_channels(hcd);
2555 : : } else {
2556 : : /*
2557 : : * Ensure NP Tx FIFO empty interrupt is disabled when
2558 : : * there are no non-periodic transfers to process.
2559 : : */
2560 : 0 : gintmsk_data_t gintmsk = {.d32 = 0 };
2561 : 0 : gintmsk.b.nptxfempty = 1;
2562 : :
2563 [ # # ]: 0 : if (fiq_enable) {
2564 : 0 : local_fiq_disable();
2565 : 0 : fiq_fsm_spin_lock(&hcd->fiq_state->lock);
2566 : 0 : DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
2567 : 0 : fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
2568 : 0 : local_fiq_enable();
2569 : : } else {
2570 : 0 : DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
2571 : : }
2572 : : }
2573 : : }
2574 : 254428328 : }
2575 : :
2576 : : #ifdef DWC_HS_ELECT_TST
2577 : : /*
2578 : : * Quick and dirty hack to implement the HS Electrical Test
2579 : : * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
2580 : : *
2581 : : * This code was copied from our userspace app "hset". It sends a
2582 : : * Get Device Descriptor control sequence in two parts, first the
2583 : : * Setup packet by itself, followed some time later by the In and
2584 : : * Ack packets. Rather than trying to figure out how to add this
2585 : : * functionality to the normal driver code, we just hijack the
2586 : : * hardware, using these two function to drive the hardware
2587 : : * directly.
2588 : : */
2589 : :
2590 : : static dwc_otg_core_global_regs_t *global_regs;
2591 : : static dwc_otg_host_global_regs_t *hc_global_regs;
2592 : : static dwc_otg_hc_regs_t *hc_regs;
2593 : : static uint32_t *data_fifo;
2594 : :
2595 : 0 : static void do_setup(void)
2596 : : {
2597 : : gintsts_data_t gintsts;
2598 : : hctsiz_data_t hctsiz;
2599 : : hcchar_data_t hcchar;
2600 : : haint_data_t haint;
2601 : : hcint_data_t hcint;
2602 : :
2603 : : /* Enable HAINTs */
2604 : 0 : DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
2605 : :
2606 : : /* Enable HCINTs */
2607 : 0 : DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
2608 : :
2609 : : /* Read GINTSTS */
2610 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2611 : :
2612 : : /* Read HAINT */
2613 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2614 : :
2615 : : /* Read HCINT */
2616 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2617 : :
2618 : : /* Read HCCHAR */
2619 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2620 : :
2621 : : /* Clear HCINT */
2622 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2623 : :
2624 : : /* Clear HAINT */
2625 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2626 : :
2627 : : /* Clear GINTSTS */
2628 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2629 : :
2630 : : /* Read GINTSTS */
2631 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2632 : :
2633 : : /*
2634 : : * Send Setup packet (Get Device Descriptor)
2635 : : */
2636 : :
2637 : : /* Make sure channel is disabled */
2638 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2639 [ # # ]: 0 : if (hcchar.b.chen) {
2640 : 0 : hcchar.b.chdis = 1;
2641 : : // hcchar.b.chen = 1;
2642 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
2643 : : //sleep(1);
2644 : 0 : dwc_mdelay(1000);
2645 : :
2646 : : /* Read GINTSTS */
2647 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2648 : :
2649 : : /* Read HAINT */
2650 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2651 : :
2652 : : /* Read HCINT */
2653 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2654 : :
2655 : : /* Read HCCHAR */
2656 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2657 : :
2658 : : /* Clear HCINT */
2659 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2660 : :
2661 : : /* Clear HAINT */
2662 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2663 : :
2664 : : /* Clear GINTSTS */
2665 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2666 : :
2667 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2668 : : }
2669 : :
2670 : : /* Set HCTSIZ */
2671 : 0 : hctsiz.d32 = 0;
2672 : 0 : hctsiz.b.xfersize = 8;
2673 : 0 : hctsiz.b.pktcnt = 1;
2674 : 0 : hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
2675 : 0 : DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
2676 : :
2677 : : /* Set HCCHAR */
2678 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2679 : 0 : hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
2680 : 0 : hcchar.b.epdir = 0;
2681 : 0 : hcchar.b.epnum = 0;
2682 : 0 : hcchar.b.mps = 8;
2683 : 0 : hcchar.b.chen = 1;
2684 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
2685 : :
2686 : : /* Fill FIFO with Setup data for Get Device Descriptor */
2687 : 0 : data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
2688 : 0 : DWC_WRITE_REG32(data_fifo++, 0x01000680);
2689 : 0 : DWC_WRITE_REG32(data_fifo++, 0x00080000);
2690 : :
2691 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2692 : :
2693 : : /* Wait for host channel interrupt */
2694 : : do {
2695 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2696 [ # # ]: 0 : } while (gintsts.b.hcintr == 0);
2697 : :
2698 : : /* Disable HCINTs */
2699 : 0 : DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
2700 : :
2701 : : /* Disable HAINTs */
2702 : 0 : DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
2703 : :
2704 : : /* Read HAINT */
2705 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2706 : :
2707 : : /* Read HCINT */
2708 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2709 : :
2710 : : /* Read HCCHAR */
2711 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2712 : :
2713 : : /* Clear HCINT */
2714 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2715 : :
2716 : : /* Clear HAINT */
2717 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2718 : :
2719 : : /* Clear GINTSTS */
2720 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2721 : :
2722 : : /* Read GINTSTS */
2723 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2724 : 0 : }
2725 : :
2726 : 0 : static void do_in_ack(void)
2727 : : {
2728 : : gintsts_data_t gintsts;
2729 : : hctsiz_data_t hctsiz;
2730 : : hcchar_data_t hcchar;
2731 : : haint_data_t haint;
2732 : : hcint_data_t hcint;
2733 : : host_grxsts_data_t grxsts;
2734 : :
2735 : : /* Enable HAINTs */
2736 : 0 : DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
2737 : :
2738 : : /* Enable HCINTs */
2739 : 0 : DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
2740 : :
2741 : : /* Read GINTSTS */
2742 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2743 : :
2744 : : /* Read HAINT */
2745 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2746 : :
2747 : : /* Read HCINT */
2748 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2749 : :
2750 : : /* Read HCCHAR */
2751 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2752 : :
2753 : : /* Clear HCINT */
2754 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2755 : :
2756 : : /* Clear HAINT */
2757 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2758 : :
2759 : : /* Clear GINTSTS */
2760 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2761 : :
2762 : : /* Read GINTSTS */
2763 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2764 : :
2765 : : /*
2766 : : * Receive Control In packet
2767 : : */
2768 : :
2769 : : /* Make sure channel is disabled */
2770 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2771 [ # # ]: 0 : if (hcchar.b.chen) {
2772 : 0 : hcchar.b.chdis = 1;
2773 : 0 : hcchar.b.chen = 1;
2774 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
2775 : : //sleep(1);
2776 : 0 : dwc_mdelay(1000);
2777 : :
2778 : : /* Read GINTSTS */
2779 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2780 : :
2781 : : /* Read HAINT */
2782 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2783 : :
2784 : : /* Read HCINT */
2785 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2786 : :
2787 : : /* Read HCCHAR */
2788 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2789 : :
2790 : : /* Clear HCINT */
2791 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2792 : :
2793 : : /* Clear HAINT */
2794 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2795 : :
2796 : : /* Clear GINTSTS */
2797 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2798 : :
2799 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2800 : : }
2801 : :
2802 : : /* Set HCTSIZ */
2803 : 0 : hctsiz.d32 = 0;
2804 : 0 : hctsiz.b.xfersize = 8;
2805 : 0 : hctsiz.b.pktcnt = 1;
2806 : 0 : hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
2807 : 0 : DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
2808 : :
2809 : : /* Set HCCHAR */
2810 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2811 : 0 : hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
2812 : 0 : hcchar.b.epdir = 1;
2813 : 0 : hcchar.b.epnum = 0;
2814 : 0 : hcchar.b.mps = 8;
2815 : 0 : hcchar.b.chen = 1;
2816 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
2817 : :
2818 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2819 : :
2820 : : /* Wait for receive status queue interrupt */
2821 : : do {
2822 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2823 [ # # ]: 0 : } while (gintsts.b.rxstsqlvl == 0);
2824 : :
2825 : : /* Read RXSTS */
2826 : 0 : grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
2827 : :
2828 : : /* Clear RXSTSQLVL in GINTSTS */
2829 : 0 : gintsts.d32 = 0;
2830 : 0 : gintsts.b.rxstsqlvl = 1;
2831 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2832 : :
2833 [ # # ]: 0 : switch (grxsts.b.pktsts) {
2834 : : case DWC_GRXSTS_PKTSTS_IN:
2835 : : /* Read the data into the host buffer */
2836 [ # # ]: 0 : if (grxsts.b.bcnt > 0) {
2837 : : int i;
2838 : 0 : int word_count = (grxsts.b.bcnt + 3) / 4;
2839 : :
2840 : 0 : data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
2841 : :
2842 [ # # ]: 0 : for (i = 0; i < word_count; i++) {
2843 : 0 : (void)DWC_READ_REG32(data_fifo++);
2844 : : }
2845 : : }
2846 : : break;
2847 : :
2848 : : default:
2849 : : break;
2850 : : }
2851 : :
2852 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2853 : :
2854 : : /* Wait for receive status queue interrupt */
2855 : : do {
2856 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2857 [ # # ]: 0 : } while (gintsts.b.rxstsqlvl == 0);
2858 : :
2859 : : /* Read RXSTS */
2860 : 0 : grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
2861 : :
2862 : : /* Clear RXSTSQLVL in GINTSTS */
2863 : 0 : gintsts.d32 = 0;
2864 : 0 : gintsts.b.rxstsqlvl = 1;
2865 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2866 : :
2867 : : switch (grxsts.b.pktsts) {
2868 : : case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
2869 : : break;
2870 : :
2871 : : default:
2872 : : break;
2873 : : }
2874 : :
2875 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2876 : :
2877 : : /* Wait for host channel interrupt */
2878 : : do {
2879 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2880 [ # # ]: 0 : } while (gintsts.b.hcintr == 0);
2881 : :
2882 : : /* Read HAINT */
2883 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2884 : :
2885 : : /* Read HCINT */
2886 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2887 : :
2888 : : /* Read HCCHAR */
2889 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2890 : :
2891 : : /* Clear HCINT */
2892 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2893 : :
2894 : : /* Clear HAINT */
2895 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2896 : :
2897 : : /* Clear GINTSTS */
2898 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2899 : :
2900 : : /* Read GINTSTS */
2901 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2902 : :
2903 : : // usleep(100000);
2904 : : // mdelay(100);
2905 : 0 : dwc_mdelay(1);
2906 : :
2907 : : /*
2908 : : * Send handshake packet
2909 : : */
2910 : :
2911 : : /* Read HAINT */
2912 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2913 : :
2914 : : /* Read HCINT */
2915 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2916 : :
2917 : : /* Read HCCHAR */
2918 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2919 : :
2920 : : /* Clear HCINT */
2921 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2922 : :
2923 : : /* Clear HAINT */
2924 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2925 : :
2926 : : /* Clear GINTSTS */
2927 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2928 : :
2929 : : /* Read GINTSTS */
2930 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2931 : :
2932 : : /* Make sure channel is disabled */
2933 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2934 [ # # ]: 0 : if (hcchar.b.chen) {
2935 : 0 : hcchar.b.chdis = 1;
2936 : 0 : hcchar.b.chen = 1;
2937 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
2938 : : //sleep(1);
2939 : 0 : dwc_mdelay(1000);
2940 : :
2941 : : /* Read GINTSTS */
2942 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2943 : :
2944 : : /* Read HAINT */
2945 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2946 : :
2947 : : /* Read HCINT */
2948 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2949 : :
2950 : : /* Read HCCHAR */
2951 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2952 : :
2953 : : /* Clear HCINT */
2954 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
2955 : :
2956 : : /* Clear HAINT */
2957 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
2958 : :
2959 : : /* Clear GINTSTS */
2960 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
2961 : :
2962 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2963 : : }
2964 : :
2965 : : /* Set HCTSIZ */
2966 : 0 : hctsiz.d32 = 0;
2967 : 0 : hctsiz.b.xfersize = 0;
2968 : 0 : hctsiz.b.pktcnt = 1;
2969 : 0 : hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
2970 : 0 : DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
2971 : :
2972 : : /* Set HCCHAR */
2973 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
2974 : 0 : hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
2975 : 0 : hcchar.b.epdir = 0;
2976 : 0 : hcchar.b.epnum = 0;
2977 : 0 : hcchar.b.mps = 8;
2978 : 0 : hcchar.b.chen = 1;
2979 : 0 : DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
2980 : :
2981 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2982 : :
2983 : : /* Wait for host channel interrupt */
2984 : : do {
2985 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
2986 [ # # ]: 0 : } while (gintsts.b.hcintr == 0);
2987 : :
2988 : : /* Disable HCINTs */
2989 : 0 : DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
2990 : :
2991 : : /* Disable HAINTs */
2992 : 0 : DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
2993 : :
2994 : : /* Read HAINT */
2995 : 0 : haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
2996 : :
2997 : : /* Read HCINT */
2998 : 0 : hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
2999 : :
3000 : : /* Read HCCHAR */
3001 : 0 : hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
3002 : :
3003 : : /* Clear HCINT */
3004 : 0 : DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
3005 : :
3006 : : /* Clear HAINT */
3007 : 0 : DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
3008 : :
3009 : : /* Clear GINTSTS */
3010 : 0 : DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
3011 : :
3012 : : /* Read GINTSTS */
3013 : 0 : gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
3014 : 0 : }
3015 : : #endif
3016 : :
3017 : : /** Handles hub class-specific requests. */
3018 : 5220 : int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
3019 : : uint16_t typeReq,
3020 : : uint16_t wValue,
3021 : : uint16_t wIndex, uint8_t * buf, uint16_t wLength)
3022 : : {
3023 : : int retval = 0;
3024 : :
3025 : 5220 : dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
3026 : : usb_hub_descriptor_t *hub_desc;
3027 : : hprt0_data_t hprt0 = {.d32 = 0 };
3028 : :
3029 : : uint32_t port_status;
3030 : :
3031 [ - + + + : 5220 : switch (typeReq) {
+ + - - ]
3032 : : case UCR_CLEAR_HUB_FEATURE:
3033 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3034 : : "ClearHubFeature 0x%x\n", wValue);
3035 [ # # ]: 0 : switch (wValue) {
3036 : : case UHF_C_HUB_LOCAL_POWER:
3037 : : case UHF_C_HUB_OVER_CURRENT:
3038 : : /* Nothing required here */
3039 : : break;
3040 : : default:
3041 : : retval = -DWC_E_INVALID;
3042 : 0 : DWC_ERROR("DWC OTG HCD - "
3043 : : "ClearHubFeature request %xh unknown\n",
3044 : : wValue);
3045 : : }
3046 : : break;
3047 : : case UCR_CLEAR_PORT_FEATURE:
3048 : : #ifdef CONFIG_USB_DWC_OTG_LPM
3049 : : if (wValue != UHF_PORT_L1)
3050 : : #endif
3051 [ + - ]: 1212 : if (!wIndex || wIndex > 1)
3052 : : goto error;
3053 : :
3054 [ - - - + : 1212 : switch (wValue) {
+ - - - -
- ]
3055 : : case UHF_PORT_ENABLE:
3056 : : DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
3057 : : "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
3058 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3059 : 0 : hprt0.b.prtena = 1;
3060 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3061 : 0 : break;
3062 : : case UHF_PORT_SUSPEND:
3063 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3064 : : "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
3065 : :
3066 [ # # ]: 0 : if (core_if->power_down == 2) {
3067 : 0 : dwc_otg_host_hibernation_restore(core_if, 0, 0);
3068 : : } else {
3069 : 0 : DWC_WRITE_REG32(core_if->pcgcctl, 0);
3070 : 0 : dwc_mdelay(5);
3071 : :
3072 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3073 : 0 : hprt0.b.prtres = 1;
3074 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3075 : 0 : hprt0.b.prtsusp = 0;
3076 : : /* Clear Resume bit */
3077 : 0 : dwc_mdelay(100);
3078 : 0 : hprt0.b.prtres = 0;
3079 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3080 : : }
3081 : : break;
3082 : : #ifdef CONFIG_USB_DWC_OTG_LPM
3083 : : case UHF_PORT_L1:
3084 : : {
3085 : : pcgcctl_data_t pcgcctl = {.d32 = 0 };
3086 : : glpmcfg_data_t lpmcfg = {.d32 = 0 };
3087 : :
3088 : : lpmcfg.d32 =
3089 : : DWC_READ_REG32(&core_if->
3090 : : core_global_regs->glpmcfg);
3091 : : lpmcfg.b.en_utmi_sleep = 0;
3092 : : lpmcfg.b.hird_thres &= (~(1 << 4));
3093 : : lpmcfg.b.prt_sleep_sts = 1;
3094 : : DWC_WRITE_REG32(&core_if->
3095 : : core_global_regs->glpmcfg,
3096 : : lpmcfg.d32);
3097 : :
3098 : : /* Clear Enbl_L1Gating bit. */
3099 : : pcgcctl.b.enbl_sleep_gating = 1;
3100 : : DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
3101 : : 0);
3102 : :
3103 : : dwc_mdelay(5);
3104 : :
3105 : : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3106 : : hprt0.b.prtres = 1;
3107 : : DWC_WRITE_REG32(core_if->host_if->hprt0,
3108 : : hprt0.d32);
3109 : : /* This bit will be cleared in wakeup interrupt handle */
3110 : : break;
3111 : : }
3112 : : #endif
3113 : : case UHF_PORT_POWER:
3114 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3115 : : "ClearPortFeature USB_PORT_FEAT_POWER\n");
3116 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3117 : 0 : hprt0.b.prtpwr = 0;
3118 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3119 : 0 : break;
3120 : : case UHF_PORT_INDICATOR:
3121 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3122 : : "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
3123 : : /* Port inidicator not supported */
3124 : : break;
3125 : : case UHF_C_PORT_CONNECTION:
3126 : : /* Clears drivers internal connect status change
3127 : : * flag */
3128 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3129 : : "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
3130 : 404 : dwc_otg_hcd->flags.b.port_connect_status_change = 0;
3131 : 404 : break;
3132 : : case UHF_C_PORT_RESET:
3133 : : /* Clears the driver's internal Port Reset Change
3134 : : * flag */
3135 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3136 : : "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
3137 : 808 : dwc_otg_hcd->flags.b.port_reset_change = 0;
3138 : 808 : break;
3139 : : case UHF_C_PORT_ENABLE:
3140 : : /* Clears the driver's internal Port
3141 : : * Enable/Disable Change flag */
3142 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3143 : : "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
3144 : 0 : dwc_otg_hcd->flags.b.port_enable_change = 0;
3145 : 0 : break;
3146 : : case UHF_C_PORT_SUSPEND:
3147 : : /* Clears the driver's internal Port Suspend
3148 : : * Change flag, which is set when resume signaling on
3149 : : * the host port is complete */
3150 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3151 : : "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
3152 : 0 : dwc_otg_hcd->flags.b.port_suspend_change = 0;
3153 : 0 : break;
3154 : : #ifdef CONFIG_USB_DWC_OTG_LPM
3155 : : case UHF_C_PORT_L1:
3156 : : dwc_otg_hcd->flags.b.port_l1_change = 0;
3157 : : break;
3158 : : #endif
3159 : : case UHF_C_PORT_OVER_CURRENT:
3160 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3161 : : "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
3162 : 0 : dwc_otg_hcd->flags.b.port_over_current_change = 0;
3163 : 0 : break;
3164 : : default:
3165 : : retval = -DWC_E_INVALID;
3166 : 0 : DWC_ERROR("DWC OTG HCD - "
3167 : : "ClearPortFeature request %xh "
3168 : : "unknown or unsupported\n", wValue);
3169 : : }
3170 : : break;
3171 : : case UCR_GET_HUB_DESCRIPTOR:
3172 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3173 : : "GetHubDescriptor\n");
3174 : : hub_desc = (usb_hub_descriptor_t *) buf;
3175 : 404 : hub_desc->bDescLength = 9;
3176 : 404 : hub_desc->bDescriptorType = 0x29;
3177 : 404 : hub_desc->bNbrPorts = 1;
3178 : 404 : USETW(hub_desc->wHubCharacteristics, 0x08);
3179 : 404 : hub_desc->bPwrOn2PwrGood = 1;
3180 : 404 : hub_desc->bHubContrCurrent = 0;
3181 : 404 : hub_desc->DeviceRemovable[0] = 0;
3182 : 404 : hub_desc->DeviceRemovable[1] = 0xff;
3183 : 404 : break;
3184 : : case UCR_GET_HUB_STATUS:
3185 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3186 : : "GetHubStatus\n");
3187 : 404 : DWC_MEMSET(buf, 0, 4);
3188 : 404 : break;
3189 : : case UCR_GET_PORT_STATUS:
3190 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3191 : : "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
3192 : : wIndex, dwc_otg_hcd->flags.d32);
3193 [ + - ]: 1988 : if (!wIndex || wIndex > 1)
3194 : : goto error;
3195 : :
3196 : 1988 : port_status = 0;
3197 : :
3198 [ + + ]: 1988 : if (dwc_otg_hcd->flags.b.port_connect_status_change)
3199 : 404 : port_status |= (1 << UHF_C_PORT_CONNECTION);
3200 : :
3201 [ - + ]: 1988 : if (dwc_otg_hcd->flags.b.port_enable_change)
3202 : 0 : port_status |= (1 << UHF_C_PORT_ENABLE);
3203 : :
3204 [ - + ]: 1988 : if (dwc_otg_hcd->flags.b.port_suspend_change)
3205 : 0 : port_status |= (1 << UHF_C_PORT_SUSPEND);
3206 : :
3207 [ - + ]: 1988 : if (dwc_otg_hcd->flags.b.port_l1_change)
3208 : 0 : port_status |= (1 << UHF_C_PORT_L1);
3209 : :
3210 [ + + ]: 1988 : if (dwc_otg_hcd->flags.b.port_reset_change) {
3211 : 808 : port_status |= (1 << UHF_C_PORT_RESET);
3212 : : }
3213 : :
3214 [ - + ]: 1988 : if (dwc_otg_hcd->flags.b.port_over_current_change) {
3215 : 0 : DWC_WARN("Overcurrent change detected\n");
3216 : 0 : port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
3217 : : }
3218 : :
3219 [ - + ]: 1988 : if (!dwc_otg_hcd->flags.b.port_connect_status) {
3220 : : /*
3221 : : * The port is disconnected, which means the core is
3222 : : * either in device mode or it soon will be. Just
3223 : : * return 0's for the remainder of the port status
3224 : : * since the port register can't be read if the core
3225 : : * is in device mode.
3226 : : */
3227 : 0 : *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
3228 : 0 : break;
3229 : : }
3230 : :
3231 : 1988 : hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
3232 : : DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
3233 : :
3234 [ + - ]: 1988 : if (hprt0.b.prtconnsts)
3235 : 1988 : port_status |= (1 << UHF_PORT_CONNECTION);
3236 : :
3237 [ + + ]: 1988 : if (hprt0.b.prtena)
3238 : 1180 : port_status |= (1 << UHF_PORT_ENABLE);
3239 : :
3240 [ - + ]: 1988 : if (hprt0.b.prtsusp)
3241 : 0 : port_status |= (1 << UHF_PORT_SUSPEND);
3242 : :
3243 [ - + ]: 1988 : if (hprt0.b.prtovrcurract)
3244 : 0 : port_status |= (1 << UHF_PORT_OVER_CURRENT);
3245 : :
3246 [ - + ]: 1988 : if (hprt0.b.prtrst)
3247 : 0 : port_status |= (1 << UHF_PORT_RESET);
3248 : :
3249 [ + - ]: 1988 : if (hprt0.b.prtpwr)
3250 : 1988 : port_status |= (1 << UHF_PORT_POWER);
3251 : :
3252 [ - + ]: 1988 : if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
3253 : 0 : port_status |= (1 << UHF_PORT_HIGH_SPEED);
3254 [ - + ]: 1988 : else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
3255 : 0 : port_status |= (1 << UHF_PORT_LOW_SPEED);
3256 : :
3257 [ - + ]: 1988 : if (hprt0.b.prttstctl)
3258 : 0 : port_status |= (1 << UHF_PORT_TEST);
3259 [ - + ]: 1988 : if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
3260 : 0 : port_status |= (1 << UHF_PORT_L1);
3261 : : }
3262 : : /*
3263 : : For Synopsys HW emulation of Power down wkup_control asserts the
3264 : : hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
3265 : : We intentionally tell the software that port is in L2Suspend state.
3266 : : Only for STE.
3267 : : */
3268 [ - + ]: 1988 : if ((core_if->power_down == 2)
3269 [ # # ]: 0 : && (core_if->hibernation_suspend == 1)) {
3270 : 0 : port_status |= (1 << UHF_PORT_SUSPEND);
3271 : : }
3272 : : /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
3273 : :
3274 : 1988 : *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
3275 : :
3276 : 1988 : break;
3277 : : case UCR_SET_HUB_FEATURE:
3278 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3279 : : "SetHubFeature\n");
3280 : : /* No HUB features supported */
3281 : : break;
3282 : : case UCR_SET_PORT_FEATURE:
3283 [ + - ]: 1212 : if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
3284 : : goto error;
3285 : :
3286 [ + + ]: 1212 : if (!dwc_otg_hcd->flags.b.port_connect_status) {
3287 : : /*
3288 : : * The port is disconnected, which means the core is
3289 : : * either in device mode or it soon will be. Just
3290 : : * return without doing anything since the port
3291 : : * register can't be written if the core is in device
3292 : : * mode.
3293 : : */
3294 : : break;
3295 : : }
3296 : :
3297 [ - - + - : 808 : switch (wValue) {
- - ]
3298 : : case UHF_PORT_SUSPEND:
3299 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3300 : : "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
3301 [ # # ]: 0 : if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
3302 : : goto error;
3303 : : }
3304 [ # # ]: 0 : if (core_if->power_down == 2) {
3305 : : int timeout = 300;
3306 : : dwc_irqflags_t flags;
3307 : 0 : pcgcctl_data_t pcgcctl = {.d32 = 0 };
3308 : 0 : gpwrdn_data_t gpwrdn = {.d32 = 0 };
3309 : : gusbcfg_data_t gusbcfg = {.d32 = 0 };
3310 : : #ifdef DWC_DEV_SRPCAP
3311 : : int32_t otg_cap_param = core_if->core_params->otg_cap;
3312 : : #endif
3313 : 0 : DWC_PRINTF("Preparing for complete power-off\n");
3314 : :
3315 : : /* Save registers before hibernation */
3316 : 0 : dwc_otg_save_global_regs(core_if);
3317 : 0 : dwc_otg_save_host_regs(core_if);
3318 : :
3319 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3320 : 0 : hprt0.b.prtsusp = 1;
3321 : 0 : hprt0.b.prtena = 0;
3322 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3323 : : /* Spin hprt0.b.prtsusp to became 1 */
3324 : : do {
3325 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3326 [ # # ]: 0 : if (hprt0.b.prtsusp) {
3327 : : break;
3328 : : }
3329 : 0 : dwc_mdelay(1);
3330 [ # # ]: 0 : } while (--timeout);
3331 [ # # ]: 0 : if (!timeout) {
3332 : 0 : DWC_WARN("Suspend wasn't genereted\n");
3333 : : }
3334 : 0 : dwc_udelay(10);
3335 : :
3336 : : /*
3337 : : * We need to disable interrupts to prevent servicing of any IRQ
3338 : : * during going to hibernation
3339 : : */
3340 : 0 : DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
3341 : 0 : core_if->lx_state = DWC_OTG_L2;
3342 : : #ifdef DWC_DEV_SRPCAP
3343 : : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3344 : : hprt0.b.prtpwr = 0;
3345 : : hprt0.b.prtena = 0;
3346 : : DWC_WRITE_REG32(core_if->host_if->hprt0,
3347 : : hprt0.d32);
3348 : : #endif
3349 : : gusbcfg.d32 =
3350 : 0 : DWC_READ_REG32(&core_if->core_global_regs->
3351 : : gusbcfg);
3352 [ # # ]: 0 : if (gusbcfg.b.ulpi_utmi_sel == 1) {
3353 : : /* ULPI interface */
3354 : : /* Suspend the Phy Clock */
3355 : : pcgcctl.d32 = 0;
3356 : 0 : pcgcctl.b.stoppclk = 1;
3357 : 0 : DWC_MODIFY_REG32(core_if->pcgcctl, 0,
3358 : : pcgcctl.d32);
3359 : 0 : dwc_udelay(10);
3360 : 0 : gpwrdn.b.pmuactv = 1;
3361 : 0 : DWC_MODIFY_REG32(&core_if->
3362 : : core_global_regs->
3363 : : gpwrdn, 0, gpwrdn.d32);
3364 : : } else {
3365 : : /* UTMI+ Interface */
3366 : 0 : gpwrdn.b.pmuactv = 1;
3367 : 0 : DWC_MODIFY_REG32(&core_if->
3368 : : core_global_regs->
3369 : : gpwrdn, 0, gpwrdn.d32);
3370 : 0 : dwc_udelay(10);
3371 : 0 : pcgcctl.b.stoppclk = 1;
3372 : 0 : DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
3373 : 0 : dwc_udelay(10);
3374 : : }
3375 : : #ifdef DWC_DEV_SRPCAP
3376 : : gpwrdn.d32 = 0;
3377 : : gpwrdn.b.dis_vbus = 1;
3378 : : DWC_MODIFY_REG32(&core_if->core_global_regs->
3379 : : gpwrdn, 0, gpwrdn.d32);
3380 : : #endif
3381 : 0 : gpwrdn.d32 = 0;
3382 : 0 : gpwrdn.b.pmuintsel = 1;
3383 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
3384 : : gpwrdn, 0, gpwrdn.d32);
3385 : 0 : dwc_udelay(10);
3386 : :
3387 : 0 : gpwrdn.d32 = 0;
3388 : : #ifdef DWC_DEV_SRPCAP
3389 : : gpwrdn.b.srp_det_msk = 1;
3390 : : #endif
3391 : 0 : gpwrdn.b.disconn_det_msk = 1;
3392 : 0 : gpwrdn.b.lnstchng_msk = 1;
3393 : 0 : gpwrdn.b.sts_chngint_msk = 1;
3394 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
3395 : : gpwrdn, 0, gpwrdn.d32);
3396 : 0 : dwc_udelay(10);
3397 : :
3398 : : /* Enable Power Down Clamp and all interrupts in GPWRDN */
3399 : 0 : gpwrdn.d32 = 0;
3400 : 0 : gpwrdn.b.pwrdnclmp = 1;
3401 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
3402 : : gpwrdn, 0, gpwrdn.d32);
3403 : 0 : dwc_udelay(10);
3404 : :
3405 : : /* Switch off VDD */
3406 : 0 : gpwrdn.d32 = 0;
3407 : 0 : gpwrdn.b.pwrdnswtch = 1;
3408 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
3409 : : gpwrdn, 0, gpwrdn.d32);
3410 : :
3411 : : #ifdef DWC_DEV_SRPCAP
3412 : : if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
3413 : : {
3414 : : core_if->pwron_timer_started = 1;
3415 : : DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
3416 : : }
3417 : : #endif
3418 : : /* Save gpwrdn register for further usage if stschng interrupt */
3419 : 0 : core_if->gr_backup->gpwrdn_local =
3420 : 0 : DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
3421 : :
3422 : : /* Set flag to indicate that we are in hibernation */
3423 : 0 : core_if->hibernation_suspend = 1;
3424 : 0 : DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
3425 : :
3426 : 0 : DWC_PRINTF("Host hibernation completed\n");
3427 : : // Exit from case statement
3428 : : break;
3429 : :
3430 : : }
3431 [ # # # # ]: 0 : if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
3432 : 0 : dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
3433 : 0 : gotgctl_data_t gotgctl = {.d32 = 0 };
3434 : 0 : gotgctl.b.hstsethnpen = 1;
3435 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
3436 : : gotgctl, 0, gotgctl.d32);
3437 : 0 : core_if->op_state = A_SUSPEND;
3438 : : }
3439 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3440 : 0 : hprt0.b.prtsusp = 1;
3441 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3442 : : {
3443 : : dwc_irqflags_t flags;
3444 : : /* Update lx_state */
3445 : 0 : DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
3446 : 0 : core_if->lx_state = DWC_OTG_L2;
3447 : 0 : DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
3448 : : }
3449 : : /* Suspend the Phy Clock */
3450 : : {
3451 : 0 : pcgcctl_data_t pcgcctl = {.d32 = 0 };
3452 : 0 : pcgcctl.b.stoppclk = 1;
3453 : 0 : DWC_MODIFY_REG32(core_if->pcgcctl, 0,
3454 : : pcgcctl.d32);
3455 : 0 : dwc_udelay(10);
3456 : : }
3457 : :
3458 : : /* For HNP the bus must be suspended for at least 200ms. */
3459 [ # # ]: 0 : if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
3460 : 0 : pcgcctl_data_t pcgcctl = {.d32 = 0 };
3461 : 0 : pcgcctl.b.stoppclk = 1;
3462 : 0 : DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
3463 : 0 : dwc_mdelay(200);
3464 : : }
3465 : :
3466 : : /** @todo - check how sw can wait for 1 sec to check asesvld??? */
3467 : : #if 0 //vahrama !!!!!!!!!!!!!!!!!!
3468 : : if (core_if->adp_enable) {
3469 : : gotgctl_data_t gotgctl = {.d32 = 0 };
3470 : : gpwrdn_data_t gpwrdn;
3471 : :
3472 : : while (gotgctl.b.asesvld == 1) {
3473 : : gotgctl.d32 =
3474 : : DWC_READ_REG32(&core_if->
3475 : : core_global_regs->
3476 : : gotgctl);
3477 : : dwc_mdelay(100);
3478 : : }
3479 : :
3480 : : /* Enable Power Down Logic */
3481 : : gpwrdn.d32 = 0;
3482 : : gpwrdn.b.pmuactv = 1;
3483 : : DWC_MODIFY_REG32(&core_if->core_global_regs->
3484 : : gpwrdn, 0, gpwrdn.d32);
3485 : :
3486 : : /* Unmask SRP detected interrupt from Power Down Logic */
3487 : : gpwrdn.d32 = 0;
3488 : : gpwrdn.b.srp_det_msk = 1;
3489 : : DWC_MODIFY_REG32(&core_if->core_global_regs->
3490 : : gpwrdn, 0, gpwrdn.d32);
3491 : :
3492 : : dwc_otg_adp_probe_start(core_if);
3493 : : }
3494 : : #endif
3495 : : break;
3496 : : case UHF_PORT_POWER:
3497 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3498 : : "SetPortFeature - USB_PORT_FEAT_POWER\n");
3499 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3500 : 0 : hprt0.b.prtpwr = 1;
3501 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3502 : 0 : break;
3503 : : case UHF_PORT_RESET:
3504 [ - + ]: 808 : if ((core_if->power_down == 2)
3505 [ # # ]: 0 : && (core_if->hibernation_suspend == 1)) {
3506 : : /* If we are going to exit from Hibernated
3507 : : * state via USB RESET.
3508 : : */
3509 : 0 : dwc_otg_host_hibernation_restore(core_if, 0, 1);
3510 : : } else {
3511 : 808 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3512 : :
3513 : : DWC_DEBUGPL(DBG_HCD,
3514 : : "DWC OTG HCD HUB CONTROL - "
3515 : : "SetPortFeature - USB_PORT_FEAT_RESET\n");
3516 : : {
3517 : 808 : pcgcctl_data_t pcgcctl = {.d32 = 0 };
3518 : 808 : pcgcctl.b.enbl_sleep_gating = 1;
3519 : 808 : pcgcctl.b.stoppclk = 1;
3520 : 808 : DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
3521 : 808 : DWC_WRITE_REG32(core_if->pcgcctl, 0);
3522 : : }
3523 : : #ifdef CONFIG_USB_DWC_OTG_LPM
3524 : : {
3525 : : glpmcfg_data_t lpmcfg;
3526 : : lpmcfg.d32 =
3527 : : DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
3528 : : if (lpmcfg.b.prt_sleep_sts) {
3529 : : lpmcfg.b.en_utmi_sleep = 0;
3530 : : lpmcfg.b.hird_thres &= (~(1 << 4));
3531 : : DWC_WRITE_REG32
3532 : : (&core_if->core_global_regs->glpmcfg,
3533 : : lpmcfg.d32);
3534 : : dwc_mdelay(1);
3535 : : }
3536 : : }
3537 : : #endif
3538 : 808 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3539 : : /* Clear suspend bit if resetting from suspended state. */
3540 : 808 : hprt0.b.prtsusp = 0;
3541 : : /* When B-Host the Port reset bit is set in
3542 : : * the Start HCD Callback function, so that
3543 : : * the reset is started within 1ms of the HNP
3544 : : * success interrupt. */
3545 [ + - ]: 808 : if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
3546 : 808 : hprt0.b.prtpwr = 1;
3547 : 808 : hprt0.b.prtrst = 1;
3548 : 808 : DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
3549 : 808 : DWC_WRITE_REG32(core_if->host_if->hprt0,
3550 : : hprt0.d32);
3551 : : }
3552 : : /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
3553 : 808 : dwc_mdelay(60);
3554 : 808 : hprt0.b.prtrst = 0;
3555 : 808 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3556 : 808 : core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
3557 : : }
3558 : : break;
3559 : : #ifdef DWC_HS_ELECT_TST
3560 : : case UHF_PORT_TEST:
3561 : : {
3562 : : uint32_t t;
3563 : : gintmsk_data_t gintmsk;
3564 : :
3565 : 0 : t = (wIndex >> 8); /* MSB wIndex USB */
3566 : : DWC_DEBUGPL(DBG_HCD,
3567 : : "DWC OTG HCD HUB CONTROL - "
3568 : : "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
3569 : : t);
3570 : 0 : DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
3571 [ # # ]: 0 : if (t < 6) {
3572 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
3573 : 0 : hprt0.b.prttstctl = t;
3574 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0,
3575 : : hprt0.d32);
3576 : : } else {
3577 : : /* Setup global vars with reg addresses (quick and
3578 : : * dirty hack, should be cleaned up)
3579 : : */
3580 : 0 : global_regs = core_if->core_global_regs;
3581 : 0 : hc_global_regs =
3582 : 0 : core_if->host_if->host_global_regs;
3583 : 0 : hc_regs =
3584 : 0 : (dwc_otg_hc_regs_t *) ((char *)
3585 : : global_regs +
3586 : : 0x500);
3587 : 0 : data_fifo =
3588 : 0 : (uint32_t *) ((char *)global_regs +
3589 : : 0x1000);
3590 : :
3591 [ # # ]: 0 : if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
3592 : : /* Save current interrupt mask */
3593 : : gintmsk.d32 =
3594 : 0 : DWC_READ_REG32
3595 : : (&global_regs->gintmsk);
3596 : :
3597 : : /* Disable all interrupts while we muck with
3598 : : * the hardware directly
3599 : : */
3600 : 0 : DWC_WRITE_REG32(&global_regs->gintmsk, 0);
3601 : :
3602 : : /* 15 second delay per the test spec */
3603 : 0 : dwc_mdelay(15000);
3604 : :
3605 : : /* Drive suspend on the root port */
3606 : 0 : hprt0.d32 =
3607 : 0 : dwc_otg_read_hprt0(core_if);
3608 : 0 : hprt0.b.prtsusp = 1;
3609 : 0 : hprt0.b.prtres = 0;
3610 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3611 : :
3612 : : /* 15 second delay per the test spec */
3613 : 0 : dwc_mdelay(15000);
3614 : :
3615 : : /* Drive resume on the root port */
3616 : 0 : hprt0.d32 =
3617 : 0 : dwc_otg_read_hprt0(core_if);
3618 : 0 : hprt0.b.prtsusp = 0;
3619 : 0 : hprt0.b.prtres = 1;
3620 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3621 : 0 : dwc_mdelay(100);
3622 : :
3623 : : /* Clear the resume bit */
3624 : 0 : hprt0.b.prtres = 0;
3625 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
3626 : :
3627 : : /* Restore interrupts */
3628 : 0 : DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
3629 [ # # ]: 0 : } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
3630 : : /* Save current interrupt mask */
3631 : : gintmsk.d32 =
3632 : 0 : DWC_READ_REG32
3633 : : (&global_regs->gintmsk);
3634 : :
3635 : : /* Disable all interrupts while we muck with
3636 : : * the hardware directly
3637 : : */
3638 : 0 : DWC_WRITE_REG32(&global_regs->gintmsk, 0);
3639 : :
3640 : : /* 15 second delay per the test spec */
3641 : 0 : dwc_mdelay(15000);
3642 : :
3643 : : /* Send the Setup packet */
3644 : 0 : do_setup();
3645 : :
3646 : : /* 15 second delay so nothing else happens for awhile */
3647 : 0 : dwc_mdelay(15000);
3648 : :
3649 : : /* Restore interrupts */
3650 : 0 : DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
3651 [ # # ]: 0 : } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
3652 : : /* Save current interrupt mask */
3653 : : gintmsk.d32 =
3654 : 0 : DWC_READ_REG32
3655 : : (&global_regs->gintmsk);
3656 : :
3657 : : /* Disable all interrupts while we muck with
3658 : : * the hardware directly
3659 : : */
3660 : 0 : DWC_WRITE_REG32(&global_regs->gintmsk, 0);
3661 : :
3662 : : /* Send the Setup packet */
3663 : 0 : do_setup();
3664 : :
3665 : : /* 15 second delay so nothing else happens for awhile */
3666 : 0 : dwc_mdelay(15000);
3667 : :
3668 : : /* Send the In and Ack packets */
3669 : 0 : do_in_ack();
3670 : :
3671 : : /* 15 second delay so nothing else happens for awhile */
3672 : 0 : dwc_mdelay(15000);
3673 : :
3674 : : /* Restore interrupts */
3675 : 0 : DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
3676 : : }
3677 : : }
3678 : : break;
3679 : : }
3680 : : #endif /* DWC_HS_ELECT_TST */
3681 : :
3682 : : case UHF_PORT_INDICATOR:
3683 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
3684 : : "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
3685 : : /* Not supported */
3686 : : break;
3687 : : default:
3688 : : retval = -DWC_E_INVALID;
3689 : 0 : DWC_ERROR("DWC OTG HCD - "
3690 : : "SetPortFeature request %xh "
3691 : : "unknown or unsupported\n", wValue);
3692 : 0 : break;
3693 : : }
3694 : : break;
3695 : : #ifdef CONFIG_USB_DWC_OTG_LPM
3696 : : case UCR_SET_AND_TEST_PORT_FEATURE:
3697 : : if (wValue != UHF_PORT_L1) {
3698 : : goto error;
3699 : : }
3700 : : {
3701 : : int portnum, hird, devaddr, remwake;
3702 : : glpmcfg_data_t lpmcfg;
3703 : : uint32_t time_usecs;
3704 : : gintsts_data_t gintsts;
3705 : : gintmsk_data_t gintmsk;
3706 : :
3707 : : if (!dwc_otg_get_param_lpm_enable(core_if)) {
3708 : : goto error;
3709 : : }
3710 : : if (wValue != UHF_PORT_L1 || wLength != 1) {
3711 : : goto error;
3712 : : }
3713 : : /* Check if the port currently is in SLEEP state */
3714 : : lpmcfg.d32 =
3715 : : DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
3716 : : if (lpmcfg.b.prt_sleep_sts) {
3717 : : DWC_INFO("Port is already in sleep mode\n");
3718 : : buf[0] = 0; /* Return success */
3719 : : break;
3720 : : }
3721 : :
3722 : : portnum = wIndex & 0xf;
3723 : : hird = (wIndex >> 4) & 0xf;
3724 : : devaddr = (wIndex >> 8) & 0x7f;
3725 : : remwake = (wIndex >> 15);
3726 : :
3727 : : if (portnum != 1) {
3728 : : retval = -DWC_E_INVALID;
3729 : : DWC_WARN
3730 : : ("Wrong port number(%d) in SetandTestPortFeature request\n",
3731 : : portnum);
3732 : : break;
3733 : : }
3734 : :
3735 : : DWC_PRINTF
3736 : : ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
3737 : : portnum, hird, devaddr, remwake);
3738 : : /* Disable LPM interrupt */
3739 : : gintmsk.d32 = 0;
3740 : : gintmsk.b.lpmtranrcvd = 1;
3741 : : DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
3742 : : gintmsk.d32, 0);
3743 : :
3744 : : if (dwc_otg_hcd_send_lpm
3745 : : (dwc_otg_hcd, devaddr, hird, remwake)) {
3746 : : retval = -DWC_E_INVALID;
3747 : : break;
3748 : : }
3749 : :
3750 : : time_usecs = 10 * (lpmcfg.b.retry_count + 1);
3751 : : /* We will consider timeout if time_usecs microseconds pass,
3752 : : * and we don't receive LPM transaction status.
3753 : : * After receiving non-error responce(ACK/NYET/STALL) from device,
3754 : : * core will set lpmtranrcvd bit.
3755 : : */
3756 : : do {
3757 : : gintsts.d32 =
3758 : : DWC_READ_REG32(&core_if->core_global_regs->gintsts);
3759 : : if (gintsts.b.lpmtranrcvd) {
3760 : : break;
3761 : : }
3762 : : dwc_udelay(1);
3763 : : } while (--time_usecs);
3764 : : /* lpm_int bit will be cleared in LPM interrupt handler */
3765 : :
3766 : : /* Now fill status
3767 : : * 0x00 - Success
3768 : : * 0x10 - NYET
3769 : : * 0x11 - Timeout
3770 : : */
3771 : : if (!gintsts.b.lpmtranrcvd) {
3772 : : buf[0] = 0x3; /* Completion code is Timeout */
3773 : : dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
3774 : : } else {
3775 : : lpmcfg.d32 =
3776 : : DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
3777 : : if (lpmcfg.b.lpm_resp == 0x3) {
3778 : : /* ACK responce from the device */
3779 : : buf[0] = 0x00; /* Success */
3780 : : } else if (lpmcfg.b.lpm_resp == 0x2) {
3781 : : /* NYET responce from the device */
3782 : : buf[0] = 0x2;
3783 : : } else {
3784 : : /* Otherwise responce with Timeout */
3785 : : buf[0] = 0x3;
3786 : : }
3787 : : }
3788 : : DWC_PRINTF("Device responce to LPM trans is %x\n",
3789 : : lpmcfg.b.lpm_resp);
3790 : : DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
3791 : : gintmsk.d32);
3792 : :
3793 : : break;
3794 : : }
3795 : : #endif /* CONFIG_USB_DWC_OTG_LPM */
3796 : : default:
3797 : : error:
3798 : : retval = -DWC_E_INVALID;
3799 : 0 : DWC_WARN("DWC OTG HCD - "
3800 : : "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
3801 : : typeReq, wIndex, wValue);
3802 : 0 : break;
3803 : : }
3804 : :
3805 : 5220 : return retval;
3806 : : }
3807 : :
3808 : : #ifdef CONFIG_USB_DWC_OTG_LPM
3809 : : /** Returns index of host channel to perform LPM transaction. */
3810 : : int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
3811 : : {
3812 : : dwc_otg_core_if_t *core_if = hcd->core_if;
3813 : : dwc_hc_t *hc;
3814 : : hcchar_data_t hcchar;
3815 : : gintmsk_data_t gintmsk = {.d32 = 0 };
3816 : :
3817 : : if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
3818 : : DWC_PRINTF("No free channel to select for LPM transaction\n");
3819 : : return -1;
3820 : : }
3821 : :
3822 : : hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
3823 : :
3824 : : /* Mask host channel interrupts. */
3825 : : gintmsk.b.hcintr = 1;
3826 : : DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
3827 : :
3828 : : /* Fill fields that core needs for LPM transaction */
3829 : : hcchar.b.devaddr = devaddr;
3830 : : hcchar.b.epnum = 0;
3831 : : hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
3832 : : hcchar.b.mps = 64;
3833 : : hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
3834 : : hcchar.b.epdir = 0; /* OUT */
3835 : : DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
3836 : : hcchar.d32);
3837 : :
3838 : : /* Remove the host channel from the free list. */
3839 : : DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
3840 : :
3841 : : DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
3842 : :
3843 : : return hc->hc_num;
3844 : : }
3845 : :
3846 : : /** Release hc after performing LPM transaction */
3847 : : void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
3848 : : {
3849 : : dwc_hc_t *hc;
3850 : : glpmcfg_data_t lpmcfg;
3851 : : uint8_t hc_num;
3852 : :
3853 : : lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
3854 : : hc_num = lpmcfg.b.lpm_chan_index;
3855 : :
3856 : : hc = hcd->hc_ptr_array[hc_num];
3857 : :
3858 : : DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
3859 : : /* Return host channel to free list */
3860 : : DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
3861 : : }
3862 : :
3863 : : int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
3864 : : uint8_t bRemoteWake)
3865 : : {
3866 : : glpmcfg_data_t lpmcfg;
3867 : : pcgcctl_data_t pcgcctl = {.d32 = 0 };
3868 : : int channel;
3869 : :
3870 : : channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
3871 : : if (channel < 0) {
3872 : : return channel;
3873 : : }
3874 : :
3875 : : pcgcctl.b.enbl_sleep_gating = 1;
3876 : : DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
3877 : :
3878 : : /* Read LPM config register */
3879 : : lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
3880 : :
3881 : : /* Program LPM transaction fields */
3882 : : lpmcfg.b.rem_wkup_en = bRemoteWake;
3883 : : lpmcfg.b.hird = hird;
3884 : : lpmcfg.b.hird_thres = 0x1c;
3885 : : lpmcfg.b.lpm_chan_index = channel;
3886 : : lpmcfg.b.en_utmi_sleep = 1;
3887 : : /* Program LPM config register */
3888 : : DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
3889 : :
3890 : : /* Send LPM transaction */
3891 : : lpmcfg.b.send_lpm = 1;
3892 : : DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
3893 : :
3894 : : return 0;
3895 : : }
3896 : :
3897 : : #endif /* CONFIG_USB_DWC_OTG_LPM */
3898 : :
3899 : 275964 : int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
3900 : : {
3901 : : int retval;
3902 : :
3903 [ + - ]: 275964 : if (port != 1) {
3904 : : return -DWC_E_INVALID;
3905 : : }
3906 : :
3907 [ + + ]: 551928 : retval = (hcd->flags.b.port_connect_status_change ||
3908 [ + - ]: 551288 : hcd->flags.b.port_reset_change ||
3909 [ + - ]: 550648 : hcd->flags.b.port_enable_change ||
3910 [ + - + - ]: 826612 : hcd->flags.b.port_suspend_change ||
3911 : 275324 : hcd->flags.b.port_over_current_change);
3912 : : #ifdef DEBUG
3913 : : if (retval) {
3914 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
3915 : : " Root port status changed\n");
3916 : : DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
3917 : : hcd->flags.b.port_connect_status_change);
3918 : : DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
3919 : : hcd->flags.b.port_reset_change);
3920 : : DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
3921 : : hcd->flags.b.port_enable_change);
3922 : : DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
3923 : : hcd->flags.b.port_suspend_change);
3924 : : DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
3925 : : hcd->flags.b.port_over_current_change);
3926 : : }
3927 : : #endif
3928 : 275964 : return retval;
3929 : : }
3930 : :
3931 : 227520310 : int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
3932 : : {
3933 : : hfnum_data_t hfnum;
3934 : 227520310 : hfnum.d32 =
3935 : 227520310 : DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
3936 : : hfnum);
3937 : :
3938 : : #ifdef DEBUG_SOF
3939 : : DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
3940 : : hfnum.b.frnum);
3941 : : #endif
3942 : 227520310 : return hfnum.b.frnum;
3943 : : }
3944 : :
3945 : 404 : int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
3946 : : struct dwc_otg_hcd_function_ops *fops)
3947 : : {
3948 : : int retval = 0;
3949 : :
3950 : 404 : hcd->fops = fops;
3951 [ + - - + ]: 808 : if (!dwc_otg_is_device_mode(hcd->core_if) &&
3952 [ # # ]: 404 : (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
3953 : 404 : dwc_otg_hcd_reinit(hcd);
3954 : : } else {
3955 : : retval = -DWC_E_NO_DEVICE;
3956 : : }
3957 : :
3958 : 404 : return retval;
3959 : : }
3960 : :
3961 : 472506 : void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
3962 : : {
3963 : 472506 : return hcd->priv;
3964 : : }
3965 : :
3966 : 404 : void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
3967 : : {
3968 : 404 : hcd->priv = priv_data;
3969 : 404 : }
3970 : :
3971 : 404 : uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
3972 : : {
3973 : 404 : return hcd->otg_port;
3974 : : }
3975 : :
3976 : 0 : uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
3977 : : {
3978 : : uint32_t is_b_host;
3979 [ # # + - ]: 808 : if (hcd->core_if->op_state == B_HOST) {
3980 : : is_b_host = 1;
3981 : : } else {
3982 : : is_b_host = 0;
3983 : : }
3984 : :
3985 : 0 : return is_b_host;
3986 : : }
3987 : :
3988 : 185636 : dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
3989 : : int iso_desc_count, int atomic_alloc)
3990 : : {
3991 : : dwc_otg_hcd_urb_t *dwc_otg_urb;
3992 : : uint32_t size;
3993 : :
3994 : 185636 : size =
3995 : : sizeof(*dwc_otg_urb) +
3996 : 185636 : iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
3997 [ + + ]: 185636 : if (atomic_alloc)
3998 : 139774 : dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
3999 : : else
4000 : 45862 : dwc_otg_urb = DWC_ALLOC(size);
4001 : :
4002 [ + - ]: 185636 : if (dwc_otg_urb)
4003 : 185636 : dwc_otg_urb->packet_count = iso_desc_count;
4004 : : else {
4005 [ # # ]: 0 : DWC_ERROR("**** DWC OTG HCD URB alloc - "
4006 : : "%salloc of %db failed\n",
4007 : : atomic_alloc?"atomic ":"", size);
4008 : : }
4009 : 185636 : return dwc_otg_urb;
4010 : : }
4011 : :
4012 : 185636 : void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
4013 : : uint8_t dev_addr, uint8_t ep_num,
4014 : : uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
4015 : : {
4016 : : dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
4017 : : ep_type, ep_dir, mps);
4018 : : #if 0
4019 : : DWC_PRINTF
4020 : : ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
4021 : : dev_addr, ep_num, ep_dir, ep_type, mps);
4022 : : #endif
4023 : 185636 : }
4024 : :
4025 : 185630 : void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
4026 : : void *urb_handle, void *buf, dwc_dma_t dma,
4027 : : uint32_t buflen, void *setup_packet,
4028 : : dwc_dma_t setup_dma, uint32_t flags,
4029 : : uint16_t interval)
4030 : : {
4031 : 185630 : dwc_otg_urb->priv = urb_handle;
4032 : 185630 : dwc_otg_urb->buf = buf;
4033 : 185630 : dwc_otg_urb->dma = dma;
4034 : 185630 : dwc_otg_urb->length = buflen;
4035 : 185630 : dwc_otg_urb->setup_packet = setup_packet;
4036 : 185630 : dwc_otg_urb->setup_dma = setup_dma;
4037 : 185630 : dwc_otg_urb->flags = flags;
4038 : 185630 : dwc_otg_urb->interval = interval;
4039 : 185630 : dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
4040 : 185630 : }
4041 : :
4042 : 0 : uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
4043 : : {
4044 : 0 : return dwc_otg_urb->status;
4045 : : }
4046 : :
4047 : 181614 : uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
4048 : : {
4049 : 181614 : return dwc_otg_urb->actual_length;
4050 : : }
4051 : :
4052 : 0 : uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
4053 : : {
4054 : 0 : return dwc_otg_urb->error_count;
4055 : : }
4056 : :
4057 : 0 : void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
4058 : : int desc_num, uint32_t offset,
4059 : : uint32_t length)
4060 : : {
4061 : 0 : dwc_otg_urb->iso_descs[desc_num].offset = offset;
4062 : 0 : dwc_otg_urb->iso_descs[desc_num].length = length;
4063 : 0 : }
4064 : :
4065 : 0 : uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
4066 : : int desc_num)
4067 : : {
4068 : 0 : return dwc_otg_urb->iso_descs[desc_num].status;
4069 : : }
4070 : :
4071 : 0 : uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
4072 : : dwc_otg_urb, int desc_num)
4073 : : {
4074 : 0 : return dwc_otg_urb->iso_descs[desc_num].actual_length;
4075 : : }
4076 : :
4077 : 106276 : int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
4078 : : {
4079 : : int allocated = 0;
4080 : : dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
4081 : :
4082 [ + - ]: 106276 : if (qh) {
4083 [ + - ]: 106276 : if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
4084 : : allocated = 1;
4085 : : }
4086 : : }
4087 : 106276 : return allocated;
4088 : : }
4089 : :
4090 : 0 : int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
4091 : : {
4092 : : dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
4093 : : int freed = 0;
4094 : : DWC_ASSERT(qh, "qh is not allocated\n");
4095 : :
4096 [ # # ]: 0 : if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
4097 : : freed = 1;
4098 : : }
4099 : :
4100 : 0 : return freed;
4101 : : }
4102 : :
4103 : 103870 : uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
4104 : : {
4105 : : dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
4106 : : DWC_ASSERT(qh, "qh is not allocated\n");
4107 : 103870 : return qh->usecs;
4108 : : }
4109 : :
4110 : 0 : void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
4111 : : {
4112 : : #ifdef DEBUG
4113 : : int num_channels;
4114 : : int i;
4115 : : gnptxsts_data_t np_tx_status;
4116 : : hptxsts_data_t p_tx_status;
4117 : :
4118 : : num_channels = hcd->core_if->core_params->host_channels;
4119 : : DWC_PRINTF("\n");
4120 : : DWC_PRINTF
4121 : : ("************************************************************\n");
4122 : : DWC_PRINTF("HCD State:\n");
4123 : : DWC_PRINTF(" Num channels: %d\n", num_channels);
4124 : : for (i = 0; i < num_channels; i++) {
4125 : : dwc_hc_t *hc = hcd->hc_ptr_array[i];
4126 : : DWC_PRINTF(" Channel %d:\n", i);
4127 : : DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
4128 : : hc->dev_addr, hc->ep_num, hc->ep_is_in);
4129 : : DWC_PRINTF(" speed: %d\n", hc->speed);
4130 : : DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
4131 : : DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
4132 : : DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
4133 : : DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
4134 : : DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
4135 : : DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
4136 : : DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
4137 : : DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
4138 : : DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
4139 : : DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
4140 : : DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
4141 : : DWC_PRINTF(" do_split: %d\n", hc->do_split);
4142 : : DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
4143 : : DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
4144 : : DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
4145 : : DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
4146 : : DWC_PRINTF(" requests: %d\n", hc->requests);
4147 : : DWC_PRINTF(" qh: %p\n", hc->qh);
4148 : : if (hc->xfer_started) {
4149 : : hfnum_data_t hfnum;
4150 : : hcchar_data_t hcchar;
4151 : : hctsiz_data_t hctsiz;
4152 : : hcint_data_t hcint;
4153 : : hcintmsk_data_t hcintmsk;
4154 : : hfnum.d32 =
4155 : : DWC_READ_REG32(&hcd->core_if->
4156 : : host_if->host_global_regs->hfnum);
4157 : : hcchar.d32 =
4158 : : DWC_READ_REG32(&hcd->core_if->host_if->
4159 : : hc_regs[i]->hcchar);
4160 : : hctsiz.d32 =
4161 : : DWC_READ_REG32(&hcd->core_if->host_if->
4162 : : hc_regs[i]->hctsiz);
4163 : : hcint.d32 =
4164 : : DWC_READ_REG32(&hcd->core_if->host_if->
4165 : : hc_regs[i]->hcint);
4166 : : hcintmsk.d32 =
4167 : : DWC_READ_REG32(&hcd->core_if->host_if->
4168 : : hc_regs[i]->hcintmsk);
4169 : : DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
4170 : : DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
4171 : : DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
4172 : : DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
4173 : : DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
4174 : : }
4175 : : if (hc->xfer_started && hc->qh) {
4176 : : dwc_otg_qtd_t *qtd;
4177 : : dwc_otg_hcd_urb_t *urb;
4178 : :
4179 : : DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
4180 : : if (!qtd->in_process)
4181 : : break;
4182 : :
4183 : : urb = qtd->urb;
4184 : : DWC_PRINTF(" URB Info:\n");
4185 : : DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
4186 : : if (urb) {
4187 : : DWC_PRINTF(" Dev: %d, EP: %d %s\n",
4188 : : dwc_otg_hcd_get_dev_addr(&urb->
4189 : : pipe_info),
4190 : : dwc_otg_hcd_get_ep_num(&urb->
4191 : : pipe_info),
4192 : : dwc_otg_hcd_is_pipe_in(&urb->
4193 : : pipe_info) ?
4194 : : "IN" : "OUT");
4195 : : DWC_PRINTF(" Max packet size: %d\n",
4196 : : dwc_otg_hcd_get_mps(&urb->
4197 : : pipe_info));
4198 : : DWC_PRINTF(" transfer_buffer: %p\n",
4199 : : urb->buf);
4200 : : DWC_PRINTF(" transfer_dma: %p\n",
4201 : : (void *)urb->dma);
4202 : : DWC_PRINTF(" transfer_buffer_length: %d\n",
4203 : : urb->length);
4204 : : DWC_PRINTF(" actual_length: %d\n",
4205 : : urb->actual_length);
4206 : : }
4207 : : }
4208 : : }
4209 : : }
4210 : : DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
4211 : : DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
4212 : : DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
4213 : : np_tx_status.d32 =
4214 : : DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
4215 : : DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
4216 : : np_tx_status.b.nptxqspcavail);
4217 : : DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
4218 : : np_tx_status.b.nptxfspcavail);
4219 : : p_tx_status.d32 =
4220 : : DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
4221 : : DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
4222 : : p_tx_status.b.ptxqspcavail);
4223 : : DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
4224 : : dwc_otg_hcd_dump_frrem(hcd);
4225 : : dwc_otg_dump_global_registers(hcd->core_if);
4226 : : dwc_otg_dump_host_registers(hcd->core_if);
4227 : : DWC_PRINTF
4228 : : ("************************************************************\n");
4229 : : DWC_PRINTF("\n");
4230 : : #endif
4231 : 0 : }
4232 : :
4233 : : #ifdef DEBUG
4234 : : void dwc_print_setup_data(uint8_t * setup)
4235 : : {
4236 : : int i;
4237 : : if (CHK_DEBUG_LEVEL(DBG_HCD)) {
4238 : : DWC_PRINTF("Setup Data = MSB ");
4239 : : for (i = 7; i >= 0; i--)
4240 : : DWC_PRINTF("%02x ", setup[i]);
4241 : : DWC_PRINTF("\n");
4242 : : DWC_PRINTF(" bmRequestType Tranfer = %s\n",
4243 : : (setup[0] & 0x80) ? "Device-to-Host" :
4244 : : "Host-to-Device");
4245 : : DWC_PRINTF(" bmRequestType Type = ");
4246 : : switch ((setup[0] & 0x60) >> 5) {
4247 : : case 0:
4248 : : DWC_PRINTF("Standard\n");
4249 : : break;
4250 : : case 1:
4251 : : DWC_PRINTF("Class\n");
4252 : : break;
4253 : : case 2:
4254 : : DWC_PRINTF("Vendor\n");
4255 : : break;
4256 : : case 3:
4257 : : DWC_PRINTF("Reserved\n");
4258 : : break;
4259 : : }
4260 : : DWC_PRINTF(" bmRequestType Recipient = ");
4261 : : switch (setup[0] & 0x1f) {
4262 : : case 0:
4263 : : DWC_PRINTF("Device\n");
4264 : : break;
4265 : : case 1:
4266 : : DWC_PRINTF("Interface\n");
4267 : : break;
4268 : : case 2:
4269 : : DWC_PRINTF("Endpoint\n");
4270 : : break;
4271 : : case 3:
4272 : : DWC_PRINTF("Other\n");
4273 : : break;
4274 : : default:
4275 : : DWC_PRINTF("Reserved\n");
4276 : : break;
4277 : : }
4278 : : DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
4279 : : DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
4280 : : DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
4281 : : DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
4282 : : }
4283 : : }
4284 : : #endif
4285 : :
4286 : 0 : void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
4287 : : {
4288 : : #if 0
4289 : : DWC_PRINTF("Frame remaining at SOF:\n");
4290 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4291 : : hcd->frrem_samples, hcd->frrem_accum,
4292 : : (hcd->frrem_samples > 0) ?
4293 : : hcd->frrem_accum / hcd->frrem_samples : 0);
4294 : :
4295 : : DWC_PRINTF("\n");
4296 : : DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
4297 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4298 : : hcd->core_if->hfnum_7_samples,
4299 : : hcd->core_if->hfnum_7_frrem_accum,
4300 : : (hcd->core_if->hfnum_7_samples >
4301 : : 0) ? hcd->core_if->hfnum_7_frrem_accum /
4302 : : hcd->core_if->hfnum_7_samples : 0);
4303 : : DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
4304 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4305 : : hcd->core_if->hfnum_0_samples,
4306 : : hcd->core_if->hfnum_0_frrem_accum,
4307 : : (hcd->core_if->hfnum_0_samples >
4308 : : 0) ? hcd->core_if->hfnum_0_frrem_accum /
4309 : : hcd->core_if->hfnum_0_samples : 0);
4310 : : DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
4311 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4312 : : hcd->core_if->hfnum_other_samples,
4313 : : hcd->core_if->hfnum_other_frrem_accum,
4314 : : (hcd->core_if->hfnum_other_samples >
4315 : : 0) ? hcd->core_if->hfnum_other_frrem_accum /
4316 : : hcd->core_if->hfnum_other_samples : 0);
4317 : :
4318 : : DWC_PRINTF("\n");
4319 : : DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
4320 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4321 : : hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
4322 : : (hcd->hfnum_7_samples_a > 0) ?
4323 : : hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
4324 : : DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
4325 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4326 : : hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
4327 : : (hcd->hfnum_0_samples_a > 0) ?
4328 : : hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
4329 : : DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
4330 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4331 : : hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
4332 : : (hcd->hfnum_other_samples_a > 0) ?
4333 : : hcd->hfnum_other_frrem_accum_a /
4334 : : hcd->hfnum_other_samples_a : 0);
4335 : :
4336 : : DWC_PRINTF("\n");
4337 : : DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
4338 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4339 : : hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
4340 : : (hcd->hfnum_7_samples_b > 0) ?
4341 : : hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
4342 : : DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
4343 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4344 : : hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
4345 : : (hcd->hfnum_0_samples_b > 0) ?
4346 : : hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
4347 : : DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
4348 : : DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
4349 : : hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
4350 : : (hcd->hfnum_other_samples_b > 0) ?
4351 : : hcd->hfnum_other_frrem_accum_b /
4352 : : hcd->hfnum_other_samples_b : 0);
4353 : : #endif
4354 : 0 : }
4355 : :
4356 : : #endif /* DWC_DEVICE_ONLY */
|