Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
891 theseven 1
#include "global.h"
2
#include "synopsysotg.h"
3
#include "usb.h"
4
#include "timer.h"
5
#include "util.h"
6
 
7
#ifndef SYNOPSYSOTG_AHB_BURST_LEN
8
#define SYNOPSYSOTG_AHB_BURST_LEN 5
9
#endif
10
#ifndef SYNOPSYSOTG_AHB_THRESHOLD
11
#define SYNOPSYSOTG_AHB_THRESHOLD 8
12
#endif
13
#ifndef SYNOPSYSOTG_TURNAROUND
14
#define SYNOPSYSOTG_TURNAROUND 3
15
#endif
16
 
17
static void synopsysotg_flush_out_endpoint(const struct usb_instance* instance, int ep)
18
{
19
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
20
    if (data->core->outep_regs[ep].doepctl.b.epena)
21
    {
22
        // 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
        synopsysotg_target_disable_irq(instance);
25
        data->core->dregs.dctl.b.sgoutnak = 1;
26
        while (!(data->core->gregs.gintsts.b.goutnakeff));
27
        union synopsysotg_depctl doepctl = { .b = { .snak = 1, .epdis = 1 } };
28
        data->core->outep_regs[ep].doepctl = doepctl;
29
        while (!(data->core->outep_regs[ep].doepint.b.epdisabled));
30
        data->core->dregs.dctl.b.cgoutnak = 1;
31
        synopsysotg_target_enable_irq(instance);
32
    }
33
    data->core->outep_regs[ep].doepctl.b.usbactep = 0;
34
    // Reset the transfer size register. Not strictly necessary, but can't hurt.
35
    data->core->outep_regs[ep].doeptsiz.d32 = 0;
36
}
37
 
38
static void synopsysotg_flush_in_endpoint(const struct usb_instance* instance, int ep)
39
{
40
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
41
    if (data->core->inep_regs[ep].diepctl.b.epena)
42
    {
43
        // 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.
45
        synopsysotg_target_disable_irq(instance);
46
        data->core->inep_regs[ep].diepctl.b.snak = 1;
47
        while (!(data->core->inep_regs[ep].diepint.b.inepnakeff));
48
        data->core->inep_regs[ep].diepctl.b.epdis = 1;
49
        while (!(data->core->inep_regs[ep].diepint.b.epdisabled));
50
        if (ep) data->core->inep_regs[ep].diepctl.b.usbactep = 0;
51
        synopsysotg_target_enable_irq(instance);
52
        // Wait for any DMA activity to stop, to make sure nobody will touch the FIFO.
53
        while (!data->core->gregs.grstctl.b.ahbidle);
54
        // Flush it all the way down!
55
        union synopsysotg_grstctl grstctl = { .b = { .txfnum = data->core->inep_regs[ep].diepctl.b.txfnum, .txfflsh = 1 } };
56
        data->core->gregs.grstctl = grstctl;
57
        while (data->core->gregs.grstctl.b.txfflsh);
58
    }
59
    else if (ep) data->core->inep_regs[ep].diepctl.b.usbactep = 0;
60
    // Reset the transfer size register. Not strictly necessary, but can't hurt.
61
    data->core->inep_regs[ep].dieptsiz.d32 = 0;
62
}
63
 
64
static void synopsysotg_flush_ints(const struct usb_instance* instance)
65
{
66
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
67
    int i;
68
    for (i = 0; i < 16; i++)
69
    {
70
        data->core->outep_regs[i].doepint = data->core->outep_regs[i].doepint;
71
        data->core->inep_regs[i].diepint = data->core->inep_regs[i].diepint;
72
    }
73
    data->core->gregs.gintsts = data->core->gregs.gintsts;
74
}
75
 
76
static void synopsysotg_try_push(const struct usb_instance* instance, int ep)
77
{
78
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
79
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
80
    union synopsysotg_depctl depctl = data->core->inep_regs[ep].diepctl;
81
    if (!depctl.b.epena || !depctl.b.usbactep || depctl.b.stall || depctl.b.naksts) return;
82
    int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
83
    if (!bytesleft) return;
84
    int maxpacket = ep ? data->core->inep_regs[ep].diepctl.b.mps : 64;
85
    union synopsysotg_hnptxsts fifospace = data->core->gregs.hnptxsts;
86
    int words = (MIN(maxpacket, bytesleft) + 3) >> 2;
87
    if (fifospace.b.nptxqspcavail && fifospace.b.nptxfspcavail << 2 >= words)
88
        while (words--) data->core->dfifo[ep][0] = *state->endpoints[ep].txaddr++;
89
    if (!words && bytesleft <= maxpacket) return;
90
    data->core->gregs.gintmsk.b.nptxfempty = true;
91
}
92
 
93
void synopsysotg_start_rx(const struct usb_instance* instance, union usb_endpoint_number ep, void* buf, int size)
94
{
95
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
96
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
97
 
98
    // Find the appropriate set of endpoint registers
99
    volatile struct synopsysotg_outepregs* regs = &data->core->outep_regs[ep.number];
100
    // Calculate number of packets (if size == 0 an empty packet will be sent)
101
    int maxpacket = regs->doepctl.b.mps;
102
    int packets = (size + maxpacket - 1) / maxpacket;
103
    if (!packets) packets = 1;
104
 
105
    // Set up data destination
106
    if (data->use_dma) regs->doepdma = buf;
107
    else state->endpoints[ep.number].rxaddr = (uint32_t*)buf;
108
    union synopsysotg_depxfrsiz deptsiz = { .b = { .pktcnt = packets, .xfersize = size } };
109
    regs->doeptsiz = deptsiz;
110
 
111
    // Flush CPU cache if necessary
112
    if (data->use_dma) invalidate_dcache(buf, size);
113
 
114
    // Enable the endpoint
115
    union synopsysotg_depctl depctl = regs->doepctl;
116
    depctl.b.epena = 1;
117
    depctl.b.cnak = 1;
118
    regs->doepctl = depctl;
119
}
120
 
121
void synopsysotg_start_tx(const struct usb_instance* instance, union usb_endpoint_number ep, const void* buf, int size)
122
{
123
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
124
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
125
 
126
    // Find the appropriate set of endpoint registers
127
    volatile struct synopsysotg_inepregs* regs = &data->core->inep_regs[ep.number];
128
    // Calculate number of packets (if size == 0 an empty packet will be sent)
129
    int maxpacket = regs->diepctl.b.mps;
130
    int packets = (size + maxpacket - 1) / maxpacket;
131
    if (!packets) packets = 1;
132
 
133
    // Set up data source
134
    if (data->use_dma) regs->diepdma = buf;
135
    else state->endpoints[ep.number].txaddr = (uint32_t*)buf;
136
    union synopsysotg_depxfrsiz deptsiz = { .b = { .pktcnt = packets, .xfersize = size } };
137
    regs->dieptsiz = deptsiz;
138
 
139
    // Flush CPU cache if necessary
140
    if (data->use_dma) clean_dcache(buf, size);
141
 
142
    // Enable the endpoint
143
    union synopsysotg_depctl depctl = regs->diepctl;
144
    depctl.b.epena = 1;
145
    depctl.b.cnak = 1;
146
    regs->diepctl = depctl;
147
 
148
    // Start pushing data into the FIFO (must be done after enabling the endpoint)
149
    if (size && !data->use_dma)
150
    {
151
        if (data->shared_txfifo) synopsysotg_try_push(instance, ep.number);
152
        else data->core->dregs.diepempmsk.ep.in |= (1 << ep.number);
153
    }
154
}
155
 
156
int synopsysotg_get_stall(const struct usb_instance* instance, union usb_endpoint_number ep)
157
{
158
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
159
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
160
        return !!data->core->inep_regs[ep.number].diepctl.b.stall;
161
    return !!data->core->outep_regs[ep.number].doepctl.b.stall;
162
}
163
 
164
void synopsysotg_set_stall(const struct usb_instance* instance, union usb_endpoint_number ep, int stall)
165
{
166
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
167
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
168
    {
169
        data->core->inep_regs[ep.number].diepctl.b.stall = !!stall;
170
        if (!stall) data->core->inep_regs[ep.number].diepctl.b.setd0pid = true;
171
    }
172
    else
173
    {
174
        data->core->outep_regs[ep.number].doepctl.b.stall = !!stall;
175
        if (!stall) data->core->outep_regs[ep.number].doepctl.b.setd0pid = true;
176
    }
177
 
178
}
179
 
180
void synopsysotg_set_address(const struct usb_instance* instance, uint8_t address)
181
{
182
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
183
    data->core->dregs.dcfg.b.devaddr = address;
184
}
185
 
186
void synopsysotg_unconfigure_ep(const struct usb_instance* instance, union usb_endpoint_number ep)
187
{
188
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
189
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
190
    {
191
        // Kill any outstanding IN transfers
192
        synopsysotg_flush_in_endpoint(instance, ep.number);
193
        // Mask interrupts for this endpoint
194
        data->core->dregs.daintmsk.ep.in &= ~(1 << ep.number);
195
    }
196
    else
197
    {
198
        // Kill any outstanding OUT transfers
199
        synopsysotg_flush_out_endpoint(instance, ep.number);
200
        // Mask interrupts for this endpoint
201
        data->core->dregs.daintmsk.ep.out &= ~(1 << ep.number);
202
    }
203
}
204
 
205
void synopsysotg_configure_ep(const struct usb_instance* instance, union usb_endpoint_number ep,
206
                              enum usb_endpoint_type type, int maxpacket)
207
{
208
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
209
 
210
    // Write the new configuration and unmask interrupts for the endpoint.
211
    // Reset data toggle to DATA0, as required by the USB specification.
212
    int txfifo = data->shared_txfifo ? 0 : ep.number;
213
    union synopsysotg_depctl depctl = { .b = { .usbactep = 1, .eptype = type, .mps = maxpacket,
214
                                               .txfnum = txfifo, .setd0pid = 1, .nextep = (ep.number + 1) & 0xf } };
215
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
216
    {
217
        data->core->inep_regs[ep.number].diepctl = depctl;
218
        data->core->dregs.daintmsk.ep.in |= (1 << ep.number);
219
    }
220
    else
221
    {
222
        data->core->outep_regs[ep.number].doepctl = depctl;
223
        data->core->dregs.daintmsk.ep.out |= (1 << ep.number);
224
    }
225
}
226
 
227
void synopsysotg_ep0_start_rx(const struct usb_instance* instance, int non_setup)
228
{
229
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
230
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
231
 
232
    // Set up data destination
233
    if (data->use_dma) data->core->outep_regs[0].doepdma = instance->buffer;
234
    else state->endpoints[0].rxaddr = (uint32_t*)instance->buffer;
235
    union synopsysotg_dep0xfrsiz deptsiz = { .b = { .supcnt = 3, .pktcnt = !!non_setup, .xfersize = 64 } };
236
    data->core->outep_regs[0].doeptsiz.d32 = deptsiz.d32;
237
 
238
    // Flush CPU cache if necessary
239
    if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
240
 
241
    // Enable the endpoint
242
    union synopsysotg_depctl depctl = data->core->outep_regs[0].doepctl;
243
    depctl.b.epena = 1;
244
    depctl.b.cnak = non_setup;
245
    data->core->outep_regs[0].doepctl = depctl;
246
}
247
 
248
void synopsysotg_ep0_start_tx(const struct usb_instance* instance, const void* buf, int len)
249
{
250
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
251
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
252
 
253
    if (len)
254
    {
255
        // Set up data source
256
        if (data->use_dma) data->core->inep_regs[0].diepdma = buf;
257
        else state->endpoints[0].txaddr = buf;
258
        union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = (len + 63) >> 6, .xfersize = len } };
259
        data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
260
    }
261
    else
262
    {
263
        // Set up the IN pipe for a zero-length packet
264
        union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = 1 } };
265
        data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
266
    }
267
 
268
    // Flush CPU cache if necessary
269
    if (data->use_dma) clean_dcache(buf, len);
270
 
271
    // Enable the endpoint
272
    union synopsysotg_depctl depctl = data->core->inep_regs[0].diepctl;
273
    depctl.b.epena = 1;
274
    depctl.b.cnak = 1;
275
    data->core->inep_regs[0].diepctl = depctl;
276
 
277
    // Start pushing data into the FIFO (must be done after enabling the endpoint)
278
    if (len && !data->use_dma)
279
    {
280
        if (data->shared_txfifo) synopsysotg_try_push(instance, 0);
281
        else data->core->dregs.diepempmsk.ep.in |= 1;
282
    }
283
}
284
 
285
static void synopsysotg_ep0_init(const struct usb_instance* instance)
286
{
287
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
288
 
289
    // Make sure both EP0 pipes are active.
290
    // (The hardware should take care of that, but who knows...)
291
    union synopsysotg_depctl depctl = { .b = { .usbactep = 1, .nextep = data->core->inep_regs[0].diepctl.b.nextep } };
292
    data->core->outep_regs[0].doepctl = depctl;
293
    data->core->inep_regs[0].diepctl = depctl;
294
}
295
 
296
void synopsysotg_irq(const struct usb_instance* instance)
297
{
298
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
299
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
300
 
301
    union synopsysotg_gintsts gintsts = data->core->gregs.gintsts;
302
 
303
    if (gintsts.b.usbreset)
304
    {
305
        data->core->dregs.dcfg.b.devaddr = 0;
306
        usb_handle_bus_reset(instance, 0);
307
    }
308
 
309
    if (gintsts.b.enumdone)
310
    {
311
        usb_handle_bus_reset(instance, data->core->dregs.dsts.b.enumspd == 0);
312
        synopsysotg_ep0_init(instance);
313
    }
314
 
315
    if (gintsts.b.rxstsqlvl && !data->use_dma)
316
    {
317
        // Device to memory part of the "software DMA" implementation, used to receive data if use_dma == 0.
318
        // Handle one packet at a time, the IRQ will re-trigger if there's something left.
319
        union synopsysotg_grxfsts rxsts = data->core->gregs.grxstsp;
320
        int ep = rxsts.b.chnum;
321
        int words = (rxsts.b.bcnt + 3) >> 2;
322
        while (words--) *state->endpoints[ep].rxaddr++ = data->core->dfifo[0][0];
323
    }
324
 
325
    if (gintsts.b.nptxfempty && data->core->gregs.gintmsk.b.nptxfempty)
326
    {
327
        // Old style, "shared TX FIFO" memory to device part of the "software DMA" implementation,
328
        // used to send data if use_dma == 0 and the device doesn't support one non-periodic TX FIFO per endpoint.
329
 
330
        // First disable the IRQ, it will be re-enabled later if there is anything left to be done.
331
        data->core->gregs.gintmsk.b.nptxfempty = false;
332
 
333
        // Check all endpoints for anything to be transmitted
334
        int ep;
335
        for (ep = 0; ep < 16; ep++) synopsysotg_try_push(instance, ep);
336
    }
337
 
338
    if (gintsts.b.inepintr)
339
    {
340
        union synopsysotg_daint daint = data->core->dregs.daint;
341
        int ep;
342
        for (ep = 0; ep < 16; ep++)
343
            if (daint.ep.in & (1 << ep))
344
            {
345
                union synopsysotg_diepintn epints = data->core->inep_regs[ep].diepint;
346
                if (epints.b.emptyintr)
347
                {
348
                    // Memory to device part of the "software DMA" implementation, used to transmit data if use_dma == 0.
349
                    union synopsysotg_depxfrsiz deptsiz = data->core->inep_regs[ep].dieptsiz;
350
                    if (!deptsiz.b.xfersize) data->core->dregs.diepempmsk.ep.in &= ~(1 << ep);
351
                    else
352
                    {
353
                        // Push data into the TX FIFO until we don't have anything left or the FIFO would overflow.
354
                        int left = (deptsiz.b.xfersize + 3) >> 2;
355
                        while (left)
356
                        {
357
                            int words = data->core->inep_regs[ep].dtxfsts.b.txfspcavail;
358
                            if (words > left) words = left;
359
                            if (!words) break;
360
                            left -= words;
361
                            while (words--) data->core->dfifo[ep][0] = *state->endpoints[ep].txaddr++;
362
                        }
363
                    }
364
                }
365
                union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_IN, .number = ep };
366
                int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
923 theseven 367
                data->core->inep_regs[ep].diepint = epints;
891 theseven 368
                if (epints.b.timeout) usb_handle_timeout(instance, epnum, bytesleft);
369
                if (epints.b.xfercompl) usb_handle_xfer_complete(instance, epnum, bytesleft);
370
            }
371
    }
372
 
373
    if (gintsts.b.outepintr)
374
    {
375
        union synopsysotg_daint daint = data->core->dregs.daint;
376
        int ep;
377
        for (ep = 0; ep < 16; ep++)
378
            if (daint.ep.out & (1 << ep))
379
            {
380
                union synopsysotg_doepintn epints = data->core->outep_regs[ep].doepint;
923 theseven 381
                data->core->outep_regs[ep].doepint = epints;
891 theseven 382
                union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_OUT, .number = ep };
383
                if (epints.b.setup)
384
                {
385
                    if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
386
                    synopsysotg_flush_in_endpoint(instance, ep);
387
                    usb_handle_setup_received(instance, epnum);
388
                }
389
                else if (epints.b.xfercompl)
390
                {
391
                    int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
392
                    usb_handle_xfer_complete(instance, epnum, bytesleft);
393
                }
394
            }
395
    }
396
 
397
    data->core->gregs.gintsts = gintsts;
398
}
399
 
400
void synopsysotg_init(const struct usb_instance* instance)
401
{
402
    int i;
403
 
404
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
405
 
406
    // Disable IRQ during setup
407
    synopsysotg_target_disable_irq(instance);
408
 
409
    // Enable OTG clocks
410
    synopsysotg_target_enable_clocks(instance);
411
 
412
    // Enable PHY clocks
413
    union synopsysotg_pcgcctl pcgcctl = { .b = {} };
414
    data->core->pcgcctl = pcgcctl;
415
 
416
    // Configure PHY type (must be done before reset)
417
    union synopsysotg_gccfg gccfg = { .b = { .disablevbussensing = 1, .pwdn = 0 } };
418
    data->core->gregs.gccfg = gccfg;
419
    union synopsysotg_gusbcfg gusbcfg = { .b = { .force_dev = 1, .usbtrdtim = SYNOPSYSOTG_TURNAROUND } };
420
    if (data->phy_16bit) gusbcfg.b.phyif = 1;
421
    else if (data->phy_ulpi) gusbcfg.b.ulpi_utmi_sel = 1;
422
    else gusbcfg.b.physel  = 1;
423
    data->core->gregs.gusbcfg = gusbcfg;
424
 
425
    // Reset the whole USB core
426
    union synopsysotg_grstctl grstctl = { .b = { .csftrst = 1 } };
427
    udelay(100);
428
    while (!data->core->gregs.grstctl.b.ahbidle);
429
    data->core->gregs.grstctl = grstctl;
430
    while (data->core->gregs.grstctl.b.csftrst);
431
    while (!data->core->gregs.grstctl.b.ahbidle);
432
 
433
    // Soft disconnect
434
    union synopsysotg_dctl dctl = { .b = { .sftdiscon = 1 } };
435
    data->core->dregs.dctl = dctl;
436
 
437
    // Configure the core
438
    union synopsysotg_gahbcfg gahbcfg = { .b = { .dmaenable = data->use_dma, .hburstlen = SYNOPSYSOTG_AHB_BURST_LEN, .glblintrmsk = 1 } };
439
    if (data->disable_double_buffering)
440
    {
441
        gahbcfg.b.nptxfemplvl_txfemplvl = 1;
442
        gahbcfg.b.ptxfemplvl = 1;
443
    }
444
    data->core->gregs.gahbcfg = gahbcfg;
445
    data->core->gregs.gusbcfg = gusbcfg;
446
    gccfg.b.pwdn = 1;
447
    data->core->gregs.gccfg = gccfg;
448
    union synopsysotg_dcfg dcfg = { .b = { .nzstsouthshk = 1 } };
449
    data->core->dregs.dcfg = dcfg;
450
 
451
    // Configure the FIFOs
452
    if (data->use_dma)
453
    {
454
        union synopsysotg_dthrctl dthrctl = { .b = { .arb_park_en = 1, .rx_thr_en = 1, .iso_thr_en = 0, .non_iso_thr_en = 0,
455
                                                     .rx_thr_len = SYNOPSYSOTG_AHB_THRESHOLD } };
456
        data->core->dregs.dthrctl = dthrctl;
457
    }
458
    int addr = data->fifosize;
459
    for (i = 0; i < 16; i++)
460
    {
461
        int size = data->txfifosize[i];
462
        addr -= size;
463
        if (size)
464
        {
465
            data->core->inep_regs[i].diepctl.b.nextep = (i + 1) & 0xf;
466
            union synopsysotg_txfsiz fsiz = { .b = { .startaddr = addr, .depth = size } };
467
            if (!i) data->core->gregs.dieptxf0_hnptxfsiz = fsiz;
468
            else data->core->gregs.dieptxf[i - 1] = fsiz;
469
        }
470
    }
471
    union synopsysotg_rxfsiz fsiz = { .b = { .depth = addr } };
472
    data->core->gregs.grxfsiz = fsiz;
473
 
474
    // Set up interrupts
475
    union synopsysotg_doepintn doepmsk =  { .b = { .xfercompl = 1, .setup = 1 } };
476
    data->core->dregs.doepmsk = doepmsk;
477
    union synopsysotg_diepintn diepmsk =  { .b = { .xfercompl = 1, .timeout = 1 } };
478
    data->core->dregs.diepmsk = diepmsk;
479
    data->core->dregs.diepempmsk.d32 = 0;
480
    union synopsysotg_daint daintmsk = { .ep = { .in = 0b0000000000000001, .out = 0b0000000000000001 } };
481
    data->core->dregs.daintmsk = daintmsk;
482
    union synopsysotg_gintmsk gintmsk =  { .b = { .usbreset = 1, .enumdone = 1, .outepintr = 1, .inepintr = 1 } };
483
    if (!data->use_dma) gintmsk.b.rxstsqlvl = 1;
484
    data->core->gregs.gintmsk = gintmsk;
485
    synopsysotg_flush_ints(instance);
486
    synopsysotg_target_clear_irq(instance);
487
    synopsysotg_target_enable_irq(instance);
488
 
489
    // Soft reconnect
490
    dctl.b.sftdiscon = 0;
491
    data->core->dregs.dctl = dctl;
492
}
493
 
494
void synopsysotg_exit(const struct usb_instance* instance)
495
{
496
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
497
 
498
    // Soft disconnect
499
    union synopsysotg_dctl dctl = { .b = { .sftdiscon = 1 } };
500
    data->core->dregs.dctl = dctl;
501
 
502
    // Disable IRQs
503
    synopsysotg_target_disable_irq(instance);
504
 
505
    // Disable clocks
506
    synopsysotg_target_disable_clocks(instance);
507
}
508
 
509
int synopsysotg_get_max_transfer_size(const struct usb_instance* data, union usb_endpoint_number ep)
510
{
511
    return 512;
512
}
513
 
514
const struct usb_driver synopsysotg_driver =
515
{
516
    .init = synopsysotg_init,
517
    .exit = synopsysotg_exit,
518
    .ep0_start_rx = synopsysotg_ep0_start_rx,
519
    .ep0_start_tx = synopsysotg_ep0_start_tx,
520
    .start_rx = synopsysotg_start_rx,
521
    .start_tx = synopsysotg_start_tx,
522
    .get_stall = synopsysotg_get_stall,
523
    .set_stall = synopsysotg_set_stall,
524
    .set_address = synopsysotg_set_address,
525
    .configure_ep = synopsysotg_configure_ep,
526
    .unconfigure_ep = synopsysotg_unconfigure_ep,
527
    .get_max_transfer_size = synopsysotg_get_max_transfer_size,
528
};
529