Subversion Repositories freemyipod

Rev

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