| Line 14... |
Line 14... |
| 14 |
#define SYNOPSYSOTG_TURNAROUND 3
|
14 |
#define SYNOPSYSOTG_TURNAROUND 3
|
| 15 |
#endif
|
15 |
#endif
|
| 16 |
|
16 |
|
| 17 |
static void synopsysotg_flush_out_endpoint(const struct usb_instance* instance, int ep)
|
17 |
static void synopsysotg_flush_out_endpoint(const struct usb_instance* instance, int ep)
|
| 18 |
{
|
18 |
{
|
| - |
|
19 |
if (!ep) return;
|
| 19 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
20 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
| 20 |
if (data->core->outep_regs[ep].doepctl.b.epena)
|
21 |
if (data->core->outep_regs[ep].doepctl.b.epena)
|
| 21 |
{
|
22 |
{
|
| 22 |
// We are waiting for an OUT packet on this endpoint, which might arrive any moment.
|
23 |
// We are waiting for an OUT packet on this endpoint, which might arrive any moment.
|
| 23 |
// Assert a global output NAK to avoid race conditions while shutting down the endpoint.
|
24 |
// Assert a global output NAK to avoid race conditions while shutting down the endpoint.
|
| 24 |
synopsysotg_target_disable_irq(instance);
|
25 |
synopsysotg_target_disable_irq(instance);
|
| 25 |
data->core->dregs.dctl.b.sgoutnak = 1;
|
26 |
data->core->dregs.dctl.b.sgoutnak = 1;
|
| 26 |
while (!(data->core->gregs.gintsts.b.goutnakeff));
|
27 |
while (!(data->core->gregs.gintsts.b.goutnakeff));
|
| 27 |
union synopsysotg_depctl doepctl = { .b = { .snak = 1, .epdis = 1 } };
|
28 |
data->core->outep_regs[ep].doepctl.b.snak = 1;
|
| 28 |
data->core->outep_regs[ep].doepctl = doepctl;
|
29 |
data->core->outep_regs[ep].doepctl.b.epdis = 1;
|
| 29 |
while (!(data->core->outep_regs[ep].doepint.b.epdisabled));
|
30 |
while (!(data->core->outep_regs[ep].doepint.b.epdisabled));
|
| 30 |
data->core->dregs.dctl.b.cgoutnak = 1;
|
31 |
data->core->dregs.dctl.b.cgoutnak = 1;
|
| 31 |
synopsysotg_target_enable_irq(instance);
|
32 |
synopsysotg_target_enable_irq(instance);
|
| 32 |
}
|
33 |
}
|
| 33 |
data->core->outep_regs[ep].doepctl.b.usbactep = 0;
|
34 |
data->core->outep_regs[ep].doepctl.b.usbactep = 0;
|
| Line 35... |
Line 36... |
| 35 |
data->core->outep_regs[ep].doeptsiz.d32 = 0;
|
36 |
data->core->outep_regs[ep].doeptsiz.d32 = 0;
|
| 36 |
}
|
37 |
}
|
| 37 |
|
38 |
|
| 38 |
static void synopsysotg_flush_in_endpoint(const struct usb_instance* instance, int ep)
|
39 |
static void synopsysotg_flush_in_endpoint(const struct usb_instance* instance, int ep)
|
| 39 |
{
|
40 |
{
|
| - |
|
41 |
if (!ep) return;
|
| 40 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
42 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
| 41 |
if (data->core->inep_regs[ep].diepctl.b.epena)
|
43 |
if (data->core->inep_regs[ep].diepctl.b.epena)
|
| 42 |
{
|
44 |
{
|
| 43 |
// We are shutting down an endpoint that might still have IN packets in the FIFO.
|
45 |
// We are shutting down an endpoint that might still have IN packets in the FIFO.
|
| 44 |
// Disable the endpoint, wait for things to settle, and flush the relevant FIFO.
|
46 |
// Disable the endpoint, wait for things to settle, and flush the relevant FIFO.
|
| 45 |
synopsysotg_target_disable_irq(instance);
|
47 |
synopsysotg_target_disable_irq(instance);
|
| 46 |
data->core->inep_regs[ep].diepctl.b.snak = 1;
|
48 |
data->core->inep_regs[ep].diepctl.b.snak = 1;
|
| 47 |
while (!(data->core->inep_regs[ep].diepint.b.inepnakeff));
|
49 |
while (!(data->core->inep_regs[ep].diepint.b.inepnakeff));
|
| 48 |
data->core->inep_regs[ep].diepctl.b.epdis = 1;
|
50 |
data->core->inep_regs[ep].diepctl.b.epdis = 1;
|
| 49 |
while (!(data->core->inep_regs[ep].diepint.b.epdisabled));
|
51 |
while (!(data->core->inep_regs[ep].diepint.b.epdisabled));
|
| 50 |
if (ep) data->core->inep_regs[ep].diepctl.b.usbactep = 0;
|
52 |
data->core->inep_regs[ep].diepctl.b.usbactep = 0;
|
| 51 |
synopsysotg_target_enable_irq(instance);
|
53 |
synopsysotg_target_enable_irq(instance);
|
| 52 |
// Wait for any DMA activity to stop, to make sure nobody will touch the FIFO.
|
54 |
// Wait for any DMA activity to stop, to make sure nobody will touch the FIFO.
|
| 53 |
while (!data->core->gregs.grstctl.b.ahbidle);
|
55 |
while (!data->core->gregs.grstctl.b.ahbidle);
|
| 54 |
// Flush it all the way down!
|
56 |
// Flush it all the way down!
|
| 55 |
union synopsysotg_grstctl grstctl = { .b = { .txfnum = data->core->inep_regs[ep].diepctl.b.txfnum, .txfflsh = 1 } };
|
57 |
union synopsysotg_grstctl grstctl = { .b = { .txfnum = data->core->inep_regs[ep].diepctl.b.txfnum, .txfflsh = 1 } };
|
| Line 159... |
Line 161... |
| 159 |
if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
|
161 |
if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
|
| 160 |
return !!data->core->inep_regs[ep.number].diepctl.b.stall;
|
162 |
return !!data->core->inep_regs[ep.number].diepctl.b.stall;
|
| 161 |
return !!data->core->outep_regs[ep.number].doepctl.b.stall;
|
163 |
return !!data->core->outep_regs[ep.number].doepctl.b.stall;
|
| 162 |
}
|
164 |
}
|
| 163 |
|
165 |
|
| 164 |
void synopsysotg_set_stall(const struct usb_instance* instance, union usb_endpoint_number ep, int stall)
|
166 |
void synopsysotg_set_stall(const struct usb_instance* instance, union usb_endpoint_number ep, bool stall)
|
| 165 |
{
|
167 |
{
|
| 166 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
168 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
| 167 |
if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
|
169 |
if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
|
| 168 |
{
|
170 |
{
|
| 169 |
data->core->inep_regs[ep.number].diepctl.b.stall = !!stall;
|
171 |
data->core->inep_regs[ep.number].diepctl.b.stall = !!stall;
|
| Line 222... |
Line 224... |
| 222 |
data->core->outep_regs[ep.number].doepctl = depctl;
|
224 |
data->core->outep_regs[ep.number].doepctl = depctl;
|
| 223 |
data->core->dregs.daintmsk.ep.out |= (1 << ep.number);
|
225 |
data->core->dregs.daintmsk.ep.out |= (1 << ep.number);
|
| 224 |
}
|
226 |
}
|
| 225 |
}
|
227 |
}
|
| 226 |
|
228 |
|
| 227 |
void synopsysotg_ep0_start_rx(const struct usb_instance* instance, int non_setup)
|
229 |
void synopsysotg_ep0_start_rx(const struct usb_instance* instance, bool non_setup, int len)
|
| 228 |
{
|
230 |
{
|
| 229 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
231 |
const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
|
| 230 |
struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
|
232 |
struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
|
| 231 |
|
233 |
|
| 232 |
// Set up data destination
|
234 |
// Set up data destination
|
| 233 |
if (data->use_dma) data->core->outep_regs[0].doepdma = instance->buffer;
|
235 |
if (data->use_dma) data->core->outep_regs[0].doepdma = instance->buffer;
|
| 234 |
else state->endpoints[0].rxaddr = (uint32_t*)instance->buffer;
|
236 |
else state->endpoints[0].rxaddr = (uint32_t*)instance->buffer;
|
| 235 |
union synopsysotg_dep0xfrsiz deptsiz = { .b = { .supcnt = 3, .pktcnt = !!non_setup, .xfersize = 64 } };
|
237 |
union synopsysotg_dep0xfrsiz deptsiz = { .b = { .supcnt = 3, .pktcnt = !!non_setup, .xfersize = len } };
|
| 236 |
data->core->outep_regs[0].doeptsiz.d32 = deptsiz.d32;
|
238 |
data->core->outep_regs[0].doeptsiz.d32 = deptsiz.d32;
|
| 237 |
|
239 |
|
| 238 |
// Flush CPU cache if necessary
|
240 |
// Flush CPU cache if necessary
|
| 239 |
if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
|
241 |
if (data->use_dma) invalidate_dcache(instance->buffer, len);
|
| 240 |
|
242 |
|
| 241 |
// Enable the endpoint
|
243 |
// Enable the endpoint
|
| 242 |
union synopsysotg_depctl depctl = data->core->outep_regs[0].doepctl;
|
244 |
union synopsysotg_depctl depctl = data->core->outep_regs[0].doepctl;
|
| 243 |
depctl.b.epena = 1;
|
245 |
depctl.b.epena = 1;
|
| 244 |
depctl.b.cnak = non_setup;
|
246 |
depctl.b.cnak = !!non_setup;
|
| 245 |
data->core->outep_regs[0].doepctl = depctl;
|
247 |
data->core->outep_regs[0].doepctl = depctl;
|
| 246 |
}
|
248 |
}
|
| 247 |
|
249 |
|
| 248 |
void synopsysotg_ep0_start_tx(const struct usb_instance* instance, const void* buf, int len)
|
250 |
void synopsysotg_ep0_start_tx(const struct usb_instance* instance, const void* buf, int len)
|
| 249 |
{
|
251 |
{
|
| Line 362... |
Line 364... |
| 362 |
}
|
364 |
}
|
| 363 |
}
|
365 |
}
|
| 364 |
}
|
366 |
}
|
| 365 |
union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_IN, .number = ep };
|
367 |
union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_IN, .number = ep };
|
| 366 |
int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
|
368 |
int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
|
| - |
|
369 |
data->core->inep_regs[ep].diepint = epints;
|
| 367 |
if (epints.b.timeout) usb_handle_timeout(instance, epnum, bytesleft);
|
370 |
if (epints.b.timeout) usb_handle_timeout(instance, epnum, bytesleft);
|
| 368 |
if (epints.b.xfercompl) usb_handle_xfer_complete(instance, epnum, bytesleft);
|
371 |
if (epints.b.xfercompl) usb_handle_xfer_complete(instance, epnum, bytesleft);
|
| 369 |
data->core->inep_regs[ep].diepint = epints;
|
- |
|
| 370 |
}
|
372 |
}
|
| 371 |
}
|
373 |
}
|
| 372 |
|
374 |
|
| 373 |
if (gintsts.b.outepintr)
|
375 |
if (gintsts.b.outepintr)
|
| 374 |
{
|
376 |
{
|
| Line 376... |
Line 378... |
| 376 |
int ep;
|
378 |
int ep;
|
| 377 |
for (ep = 0; ep < 16; ep++)
|
379 |
for (ep = 0; ep < 16; ep++)
|
| 378 |
if (daint.ep.out & (1 << ep))
|
380 |
if (daint.ep.out & (1 << ep))
|
| 379 |
{
|
381 |
{
|
| 380 |
union synopsysotg_doepintn epints = data->core->outep_regs[ep].doepint;
|
382 |
union synopsysotg_doepintn epints = data->core->outep_regs[ep].doepint;
|
| - |
|
383 |
data->core->outep_regs[ep].doepint = epints;
|
| 381 |
union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_OUT, .number = ep };
|
384 |
union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_OUT, .number = ep };
|
| 382 |
if (epints.b.setup)
|
385 |
if (epints.b.setup)
|
| 383 |
{
|
386 |
{
|
| 384 |
if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
|
387 |
if (data->use_dma) invalidate_dcache((const void*)data->core->inep_regs[ep].diepdma, 8);
|
| 385 |
synopsysotg_flush_in_endpoint(instance, ep);
|
388 |
synopsysotg_flush_in_endpoint(instance, ep);
|
| 386 |
usb_handle_setup_received(instance, epnum);
|
389 |
usb_handle_setup_received(instance, epnum);
|
| 387 |
}
|
390 |
}
|
| 388 |
else if (epints.b.xfercompl)
|
391 |
else if (epints.b.xfercompl)
|
| 389 |
{
|
392 |
{
|
| 390 |
int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
|
393 |
int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
|
| 391 |
usb_handle_xfer_complete(instance, epnum, bytesleft);
|
394 |
usb_handle_xfer_complete(instance, epnum, bytesleft);
|
| 392 |
}
|
395 |
}
|
| 393 |
data->core->outep_regs[ep].doepint = epints;
|
- |
|
| 394 |
}
|
396 |
}
|
| 395 |
}
|
397 |
}
|
| 396 |
|
398 |
|
| 397 |
data->core->gregs.gintsts = gintsts;
|
399 |
data->core->gregs.gintsts = gintsts;
|
| 398 |
}
|
400 |
}
|
| Line 456... |
Line 458... |
| 456 |
data->core->dregs.dthrctl = dthrctl;
|
458 |
data->core->dregs.dthrctl = dthrctl;
|
| 457 |
}
|
459 |
}
|
| 458 |
int addr = data->fifosize;
|
460 |
int addr = data->fifosize;
|
| 459 |
for (i = 0; i < 16; i++)
|
461 |
for (i = 0; i < 16; i++)
|
| 460 |
{
|
462 |
{
|
| - |
|
463 |
data->core->inep_regs[i].diepctl.b.nextep = (i + 1) & 0xf;
|
| 461 |
int size = data->txfifosize[i];
|
464 |
int size = data->txfifosize[i];
|
| 462 |
addr -= size;
|
465 |
addr -= size;
|
| 463 |
if (size)
|
466 |
if (size)
|
| 464 |
{
|
467 |
{
|
| 465 |
data->core->inep_regs[i].diepctl.b.nextep = (i + 1) & 0xf;
|
- |
|
| 466 |
union synopsysotg_txfsiz fsiz = { .b = { .startaddr = addr, .depth = size } };
|
468 |
union synopsysotg_txfsiz fsiz = { .b = { .startaddr = addr, .depth = size } };
|
| 467 |
if (!i) data->core->gregs.dieptxf0_hnptxfsiz = fsiz;
|
469 |
if (!i) data->core->gregs.dieptxf0_hnptxfsiz = fsiz;
|
| 468 |
else data->core->gregs.dieptxf[i - 1] = fsiz;
|
470 |
else data->core->gregs.dieptxf[i - 1] = fsiz;
|
| 469 |
}
|
471 |
}
|
| 470 |
}
|
472 |
}
|
| Line 524... |
Line 526... |
| 524 |
.set_address = synopsysotg_set_address,
|
526 |
.set_address = synopsysotg_set_address,
|
| 525 |
.configure_ep = synopsysotg_configure_ep,
|
527 |
.configure_ep = synopsysotg_configure_ep,
|
| 526 |
.unconfigure_ep = synopsysotg_unconfigure_ep,
|
528 |
.unconfigure_ep = synopsysotg_unconfigure_ep,
|
| 527 |
.get_max_transfer_size = synopsysotg_get_max_transfer_size,
|
529 |
.get_max_transfer_size = synopsysotg_get_max_transfer_size,
|
| 528 |
};
|
530 |
};
|
| - |
|
531 |
|