Subversion Repositories freemyipod

Rev

Rev 889 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
881 theseven 1
#include "global.h"
2
#include "core/synopsysotg/synopsysotg.h"
3
#include "protocol/usb/usb.h"
4
#include "sys/time.h"
5
#include "sys/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
    // If we don't expect a non-SETUP packet, we can stall the OUT pipe,
233
    // SETUP packets will ignore that.
234
    if (!non_setup) data->core->outep_regs[0].doepctl.b.stall = 1;
235
 
236
    // Set up data destination
237
    if (data->use_dma) data->core->outep_regs[0].doepdma = instance->buffer;
238
    else state->endpoints[0].rxaddr = (uint32_t*)instance->buffer;
239
    union synopsysotg_dep0xfrsiz deptsiz = { .b = { .supcnt = 3, .pktcnt = !!non_setup, .xfersize = 64 } };
240
    data->core->outep_regs[0].doeptsiz.d32 = deptsiz.d32;
241
 
242
    // Flush CPU cache if necessary
243
    if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
244
 
245
    // Enable the endpoint
246
    union synopsysotg_depctl depctl = data->core->outep_regs[0].doepctl;
247
    depctl.b.epena = 1;
248
    depctl.b.cnak = 1;
249
    data->core->outep_regs[0].doepctl = depctl;
250
}
251
 
252
void synopsysotg_ep0_start_tx(const struct usb_instance* instance, const void* buf, int len)
253
{
254
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
255
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
256
 
257
    if (len)
258
    {
259
        // Set up data source
260
        if (data->use_dma) data->core->inep_regs[0].diepdma = buf;
261
        else state->endpoints[0].txaddr = buf;
262
        union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = (len + 63) >> 6, .xfersize = len } };
263
        data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
264
    }
265
    else
266
    {
267
        // Set up the IN pipe for a zero-length packet
268
        union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = 1 } };
269
        data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
270
    }
271
 
272
    // Flush CPU cache if necessary
273
    if (data->use_dma) clean_dcache(buf, len);
274
 
275
    // Enable the endpoint
276
    union synopsysotg_depctl depctl = data->core->inep_regs[0].diepctl;
277
    depctl.b.epena = 1;
278
    depctl.b.cnak = 1;
279
    data->core->inep_regs[0].diepctl = depctl;
280
 
281
    // Start pushing data into the FIFO (must be done after enabling the endpoint)
282
    if (len && !data->use_dma)
283
    {
284
        if (data->shared_txfifo) synopsysotg_try_push(instance, 0);
285
        else data->core->dregs.diepempmsk.ep.in |= 1;
286
    }
287
}
288
 
289
static void synopsysotg_ep0_init(const struct usb_instance* instance)
290
{
291
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
292
 
293
    // Make sure both EP0 pipes are active.
294
    // (The hardware should take care of that, but who knows...)
295
    union synopsysotg_depctl depctl = { .b = { .usbactep = 1, .nextep = data->core->inep_regs[0].diepctl.b.nextep } };
296
    data->core->outep_regs[0].doepctl = depctl;
297
    data->core->inep_regs[0].diepctl = depctl;
298
 
299
    // Prime EP0 for the first setup packet.
300
    usb_ep0_expect_setup(instance);
301
}
302
 
303
void synopsysotg_irq(const struct usb_instance* instance)
304
{
305
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
306
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
307
 
308
    union synopsysotg_gintsts gintsts = data->core->gregs.gintsts;
309
 
310
    if (gintsts.b.usbreset)
311
    {
312
        data->core->dregs.dcfg.b.devaddr = 0;
313
        usb_handle_bus_reset(instance, 0);
314
    }
315
 
316
    if (gintsts.b.enumdone)
317
    {
318
        synopsysotg_ep0_init(instance);
319
        usb_handle_bus_reset(instance, data->core->dregs.dsts.b.enumspd == 0);
320
    }
321
 
322
    if (gintsts.b.rxstsqlvl)
323
    {
324
        // Device to memory part of the "software DMA" implementation, used to receive data if use_dma == 0.
325
        // Handle one packet at a time, the IRQ will re-trigger if there's something left.
326
        union synopsysotg_grxfsts rxsts = data->core->gregs.grxstsp;
327
        int ep = rxsts.b.chnum;
328
        int words = (rxsts.b.bcnt + 3) >> 2;
329
        while (words--) *state->endpoints[ep].rxaddr++ = data->core->dfifo[0][0];
330
    }
331
 
332
    if (gintsts.b.nptxfempty && data->core->gregs.gintmsk.b.nptxfempty)
333
    {
334
        // Old style, "shared TX FIFO" memory to device part of the "software DMA" implementation,
335
        // used to send data if use_dma == 0 and the device doesn't support one non-periodic TX FIFO per endpoint.
336
 
337
        // First disable the IRQ, it will be re-enabled later if there is anything left to be done.
338
        data->core->gregs.gintmsk.b.nptxfempty = false;
339
 
340
        // Check all endpoints for anything to be transmitted
341
        int ep;
342
        for (ep = 0; ep < 16; ep++) synopsysotg_try_push(instance, ep);
343
    }
344
 
345
    if (gintsts.b.inepintr)
346
    {
347
        union synopsysotg_daint daint = data->core->dregs.daint;
348
        int ep;
349
        for (ep = 0; ep < 16; ep++)
350
            if (daint.ep.in & (1 << ep))
351
            {
352
                union synopsysotg_diepintn epints = data->core->inep_regs[ep].diepint;
353
                if (epints.b.emptyintr)
354
                {
355
                    // Memory to device part of the "software DMA" implementation, used to transmit data if use_dma == 0.
356
                    union synopsysotg_depxfrsiz deptsiz = data->core->inep_regs[ep].dieptsiz;
357
                    if (!deptsiz.b.xfersize) data->core->dregs.diepempmsk.ep.in &= ~(1 << ep);
358
                    else
359
                    {
360
                        // Push data into the TX FIFO until we don't have anything left or the FIFO would overflow.
361
                        int left = (deptsiz.b.xfersize + 3) >> 2;
362
                        while (left)
363
                        {
364
                            int words = data->core->inep_regs[ep].dtxfsts.b.txfspcavail;
365
                            if (words > left) words = left;
366
                            if (!words) break;
367
                            left -= words;
368
                            while (words--) data->core->dfifo[ep][0] = *state->endpoints[ep].txaddr++;
369
                        }
370
                    }
371
                }
372
                union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_IN, .number = ep };
373
                int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
374
                if (epints.b.timeout) usb_handle_timeout(instance, epnum, bytesleft);
375
                if (epints.b.xfercompl) usb_handle_xfer_complete(instance, epnum, bytesleft);
376
                data->core->inep_regs[ep].diepint = epints;
377
            }
378
    }
379
 
380
    if (gintsts.b.outepintr)
381
    {
382
        union synopsysotg_daint daint = data->core->dregs.daint;
383
        int ep;
384
        for (ep = 0; ep < 16; ep++)
385
            if (daint.ep.out & (1 << ep))
386
            {
387
                union synopsysotg_doepintn epints = data->core->outep_regs[ep].doepint;
388
                union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_OUT, .number = ep };
389
                if (epints.b.setup)
390
                {
391
                    if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
392
                    union synopsysotg_dep0xfrsiz deptsiz = { .d32 = data->core->outep_regs[0].doeptsiz.d32 };
393
                    int back2back = 3 - deptsiz.b.supcnt;
394
                    synopsysotg_flush_in_endpoint(instance, ep);
395
                    usb_handle_setup_received(instance, epnum, back2back);
396
                }
397
                else if (epints.b.xfercompl)
398
                {
399
                    int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
400
                    usb_handle_xfer_complete(instance, epnum, bytesleft);
401
                }
402
                data->core->outep_regs[ep].doepint = epints;
403
            }
404
    }
405
 
406
    data->core->gregs.gintsts = gintsts;
407
}
408
 
409
void synopsysotg_init(const struct usb_instance* instance)
410
{
411
    int i;
412
 
413
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
414
 
415
    // Disable IRQ during setup
416
    synopsysotg_target_disable_irq(instance);
417
 
418
    // Enable OTG clocks
419
    synopsysotg_target_enable_clocks(instance);
420
 
421
    // Enable PHY clocks
422
    union synopsysotg_pcgcctl pcgcctl = { .b = {} };
423
    data->core->pcgcctl = pcgcctl;
424
 
425
    // Configure PHY type (must be done before reset)
426
    union synopsysotg_gccfg gccfg = { .b = { .disablevbussensing = 1, .pwdn = 0 } };
427
    data->core->gregs.gccfg = gccfg;
428
    union synopsysotg_gusbcfg gusbcfg = { .b = { .force_dev = 1, .usbtrdtim = SYNOPSYSOTG_TURNAROUND } };
429
    if (data->phy_16bit) gusbcfg.b.phyif = 1;
430
    else if (data->phy_ulpi) gusbcfg.b.ulpi_utmi_sel = 1;
431
    else gusbcfg.b.physel  = 1;
432
    data->core->gregs.gusbcfg = gusbcfg;
433
 
434
    // Reset the whole USB core
435
    union synopsysotg_grstctl grstctl = { .b = { .csftrst = 1 } };
436
    udelay(100);
437
    while (!data->core->gregs.grstctl.b.ahbidle);
438
    data->core->gregs.grstctl = grstctl;
439
    while (data->core->gregs.grstctl.b.csftrst);
440
    while (!data->core->gregs.grstctl.b.ahbidle);
441
 
442
    // Soft disconnect
443
    union synopsysotg_dctl dctl = { .b = { .sftdiscon = 1 } };
444
    data->core->dregs.dctl = dctl;
445
 
446
    // Configure the core
447
    union synopsysotg_gahbcfg gahbcfg = { .b = { .dmaenable = data->use_dma, .hburstlen = SYNOPSYSOTG_AHB_BURST_LEN, .glblintrmsk = 1 } };
448
    if (data->disable_double_buffering)
449
    {
450
        gahbcfg.b.nptxfemplvl_txfemplvl = 1;
451
        gahbcfg.b.ptxfemplvl = 1;
452
    }
453
    data->core->gregs.gahbcfg = gahbcfg;
454
    data->core->gregs.gusbcfg = gusbcfg;
455
    gccfg.b.pwdn = 1;
456
    data->core->gregs.gccfg = gccfg;
457
    union synopsysotg_dcfg dcfg = { .b = { .nzstsouthshk = 1 } };
458
    data->core->dregs.dcfg = dcfg;
459
 
460
    // Configure the FIFOs
461
    if (data->use_dma)
462
    {
463
        union synopsysotg_dthrctl dthrctl = { .b = { .arb_park_en = 1, .rx_thr_en = 1, .iso_thr_en = 0, .non_iso_thr_en = 0,
464
                                                     .rx_thr_len = SYNOPSYSOTG_AHB_THRESHOLD } };
465
        data->core->dregs.dthrctl = dthrctl;
466
    }
467
    int addr = data->fifosize;
468
    for (i = 0; i < 16; i++)
469
    {
470
        int size = data->txfifosize[i];
471
        addr -= size;
472
        if (size)
473
        {
474
            data->core->inep_regs[i].diepctl.b.nextep = (i + 1) & 0xf;
475
            union synopsysotg_txfsiz fsiz = { .b = { .startaddr = addr, .depth = size } };
476
            if (!i) data->core->gregs.dieptxf0_hnptxfsiz = fsiz;
477
            else data->core->gregs.dieptxf[i - 1] = fsiz;
478
        }
479
    }
480
    union synopsysotg_rxfsiz fsiz = { .b = { .depth = addr } };
481
    data->core->gregs.grxfsiz = fsiz;
482
 
483
    // Set up interrupts
484
    union synopsysotg_doepintn doepmsk =  { .b = { .xfercompl = 1, .setup = 1 } };
485
    data->core->dregs.doepmsk = doepmsk;
486
    union synopsysotg_diepintn diepmsk =  { .b = { .xfercompl = 1, .timeout = 1 } };
487
    data->core->dregs.diepmsk = diepmsk;
488
    data->core->dregs.diepempmsk.d32 = 0;
489
    union synopsysotg_daint daintmsk = { .ep = { .in = 0b0000000000000001, .out = 0b0000000000000001 } };
490
    data->core->dregs.daintmsk = daintmsk;
491
    union synopsysotg_gintmsk gintmsk =  { .b = { .usbreset = 1, .enumdone = 1, .outepintr = 1, .inepintr = 1 } };
492
    if (!data->use_dma) gintmsk.b.rxstsqlvl = 1;
493
    data->core->gregs.gintmsk = gintmsk;
494
    synopsysotg_flush_ints(instance);
495
    synopsysotg_target_clear_irq(instance);
496
    synopsysotg_target_enable_irq(instance);
497
 
498
    // Soft reconnect
499
    dctl.b.sftdiscon = 0;
500
    data->core->dregs.dctl = dctl;
501
}
502
 
503
void synopsysotg_exit(const struct usb_instance* instance)
504
{
505
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
506
 
507
    // Soft disconnect
508
    union synopsysotg_dctl dctl = { .b = { .sftdiscon = 1 } };
509
    data->core->dregs.dctl = dctl;
510
 
511
    // Disable IRQs
512
    synopsysotg_target_disable_irq(instance);
513
 
514
    // Disable clocks
515
    synopsysotg_target_disable_clocks(instance);
516
}
517
 
518
int synopsysotg_get_max_transfer_size(const struct usb_instance* data, union usb_endpoint_number ep)
519
{
520
    return 512;
521
}
522
 
523
const struct usb_driver synopsysotg_driver =
524
{
525
    .init = synopsysotg_init,
526
    .exit = synopsysotg_exit,
527
    .ep0_start_rx = synopsysotg_ep0_start_rx,
528
    .ep0_start_tx = synopsysotg_ep0_start_tx,
529
    .start_rx = synopsysotg_start_rx,
530
    .start_tx = synopsysotg_start_tx,
531
    .get_stall = synopsysotg_get_stall,
532
    .set_stall = synopsysotg_set_stall,
533
    .set_address = synopsysotg_set_address,
534
    .configure_ep = synopsysotg_configure_ep,
535
    .unconfigure_ep = synopsysotg_unconfigure_ep,
536
    .get_max_transfer_size = synopsysotg_get_max_transfer_size,
537
};