Subversion Repositories freemyipod

Rev

Rev 855 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 855 Rev 891
Line 1... Line 1...
1
//
1
#include "global.h"
2
//
2
#include "synopsysotg.h"
3
//    Copyright 2010 TheSeven
3
#include "usb.h"
4
//
4
#include "timer.h"
5
//
5
#include "util.h"
6
//    This file is part of emCORE.
6
 
7
//
7
#ifndef SYNOPSYSOTG_AHB_BURST_LEN
8
//    emCORE is free software: you can redistribute it and/or
8
#define SYNOPSYSOTG_AHB_BURST_LEN 5
9
//    modify it under the terms of the GNU General Public License as
9
#endif
10
//    published by the Free Software Foundation, either version 2 of the
10
#ifndef SYNOPSYSOTG_AHB_THRESHOLD
11
//    License, or (at your option) any later version.
11
#define SYNOPSYSOTG_AHB_THRESHOLD 8
12
//
12
#endif
13
//    emCORE is distributed in the hope that it will be useful,
13
#ifndef SYNOPSYSOTG_TURNAROUND
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
#define SYNOPSYSOTG_TURNAROUND 3
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
#endif
16
//    See the GNU General Public License for more details.
16
 
17
//
17
static void synopsysotg_flush_out_endpoint(const struct usb_instance* instance, int ep)
18
//    You should have received a copy of the GNU General Public License along
18
{
19
//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
19
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
20
//
20
    if (data->core->outep_regs[ep].doepctl.b.epena)
21
//
21
    {
22
 
22
        // We are waiting for an OUT packet on this endpoint, which might arrive any moment.
23
 
23
        // Assert a global output NAK to avoid race conditions while shutting down the endpoint.
24
#include "global.h"
24
        synopsysotg_target_disable_irq(instance);
25
#include "mmu.h"
25
        data->core->dregs.dctl.b.sgoutnak = 1;
26
#include "panic.h"
26
        while (!(data->core->gregs.gintsts.b.goutnakeff));
27
#include "usbdrv.h"
27
        union synopsysotg_depctl doepctl = { .b = { .snak = 1, .epdis = 1 } };
28
#include "thread.h"
28
        data->core->outep_regs[ep].doepctl = doepctl;
29
#include "timer.h"
29
        while (!(data->core->outep_regs[ep].doepint.b.epdisabled));
30
#include "usb.h"
30
        data->core->dregs.dctl.b.cgoutnak = 1;
31
#include "usb_ch9.h"
31
        synopsysotg_target_enable_irq(instance);
32
#include "synopsysotg.h"
32
    }
33
#include "util.h"
33
    data->core->outep_regs[ep].doepctl.b.usbactep = 0;
34
#include "interrupt.h"
34
    // Reset the transfer size register. Not strictly necessary, but can't hurt.
35
#include "clockgates.h"
35
    data->core->outep_regs[ep].doeptsiz.d32 = 0;
36
#include "power.h"
36
}
37
 
37
 
38
 
38
static void synopsysotg_flush_in_endpoint(const struct usb_instance* instance, int ep)
39
struct ep_type
39
{
40
{
40
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
41
    bool active;
41
    if (data->core->inep_regs[ep].diepctl.b.epena)
42
    bool busy;
42
    {
43
    bool done;
43
        // We are shutting down an endpoint that might still have IN packets in the FIFO.
44
    int rc;
44
        // Disable the endpoint, wait for things to settle, and flush the relevant FIFO.
45
    int size;
45
        synopsysotg_target_disable_irq(instance);
46
    struct wakeup complete;
46
        data->core->inep_regs[ep].diepctl.b.snak = 1;
47
} ;
47
        while (!(data->core->inep_regs[ep].diepint.b.inepnakeff));
48
 
48
        data->core->inep_regs[ep].diepctl.b.epdis = 1;
49
static struct ep_type endpoints[5];
49
        while (!(data->core->inep_regs[ep].diepint.b.epdisabled));
50
static struct usb_ctrlrequest ctrlreq CACHEALIGN_ATTR;
50
        if (ep) data->core->inep_regs[ep].diepctl.b.usbactep = 0;
51
static struct scheduler_thread synopsysotg_thread_handle;
51
        synopsysotg_target_enable_irq(instance);
52
static uint32_t synopsysotg_stack[0x40] STACK_ATTR;
52
        // Wait for any DMA activity to stop, to make sure nobody will touch the FIFO.
53
 
53
        while (!data->core->gregs.grstctl.b.ahbidle);
54
int usb_drv_port_speed(void)
54
        // Flush it all the way down!
55
{
55
        union synopsysotg_grstctl grstctl = { .b = { .txfnum = data->core->inep_regs[ep].diepctl.b.txfnum, .txfflsh = 1 } };
56
    return (DSTS & 2) == 0 ? 1 : 0;
56
        data->core->gregs.grstctl = grstctl;
57
}
57
        while (data->core->gregs.grstctl.b.txfflsh);
58
 
58
    }
59
static void reset_endpoints(int reinit)
59
    else if (ep) data->core->inep_regs[ep].diepctl.b.usbactep = 0;
60
{
60
    // Reset the transfer size register. Not strictly necessary, but can't hurt.
61
    unsigned int i;
61
    data->core->inep_regs[ep].dieptsiz.d32 = 0;
62
    for (i = 0; i < sizeof(endpoints)/sizeof(struct ep_type); i++)
62
}
63
    {
63
 
64
        if (reinit) endpoints[i].active = false;
64
static void synopsysotg_flush_ints(const struct usb_instance* instance)
65
        endpoints[i].busy = false;
65
{
66
        endpoints[i].rc = -1;
66
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
67
        endpoints[i].done = true;
67
    int i;
68
        wakeup_signal(&endpoints[i].complete);
68
    for (i = 0; i < 16; i++)
69
    }
69
    {
70
    DIEPCTL0 = 0x8800;  /* EP0 IN ACTIVE NEXT=1 */
70
        data->core->outep_regs[i].doepint = data->core->outep_regs[i].doepint;
71
    DOEPCTL0 = 0x8000;  /* EP0 OUT ACTIVE */
71
        data->core->inep_regs[i].diepint = data->core->inep_regs[i].diepint;
72
    DOEPTSIZ0 = 0x20080040;  /* EP0 OUT Transfer Size:
72
    }
73
                                64 Bytes, 1 Packet, 1 Setup Packet */
73
    data->core->gregs.gintsts = data->core->gregs.gintsts;
74
    DOEPDMA0 = &ctrlreq;
74
}
75
    DOEPCTL0 |= 0x84000000;  /* EP0 OUT ENABLE CLEARNAK */
75
 
76
    if (reinit)
76
static void synopsysotg_try_push(const struct usb_instance* instance, int ep)
77
    {
77
{
78
        /* The size is getting set to zero, because we don't know
78
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
79
           whether we are Full Speed or High Speed at this stage */
79
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
80
        /* EP1 IN INACTIVE DATA0 SIZE=0 NEXT=3 */
80
    union synopsysotg_depctl depctl = data->core->inep_regs[ep].diepctl;
81
        DIEPCTL1 = 0x10001800;
81
    if (!depctl.b.epena || !depctl.b.usbactep || depctl.b.stall || depctl.b.naksts) return;
82
        /* EP2 OUT INACTIVE DATA0 SIZE=0 */
82
    int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
83
        DOEPCTL2 = 0x10000000;
83
    if (!bytesleft) return;
84
        /* EP3 IN INACTIVE DATA0 SIZE=0 NEXT=0 */
84
    int maxpacket = ep ? data->core->inep_regs[ep].diepctl.b.mps : 64;
85
        DIEPCTL3 = 0x10000000;
85
    union synopsysotg_hnptxsts fifospace = data->core->gregs.hnptxsts;
86
        /* EP4 OUT INACTIVE DATA0 SIZE=0 */
86
    int words = (MIN(maxpacket, bytesleft) + 3) >> 2;
87
        DOEPCTL4 = 0x10000000;
87
    if (fifospace.b.nptxqspcavail && fifospace.b.nptxfspcavail << 2 >= words)
88
    }
88
        while (words--) data->core->dfifo[ep][0] = *state->endpoints[ep].txaddr++;
89
    else
89
    if (!words && bytesleft <= maxpacket) return;
90
    {
90
    data->core->gregs.gintmsk.b.nptxfempty = true;
91
        /* INACTIVE DATA0 */
91
}
92
        DIEPCTL1 = (DIEPCTL1 & ~0x00008000) | 0x10000000;
92
 
93
        DOEPCTL2 = (DOEPCTL2 & ~0x00008000) | 0x10000000;
93
void synopsysotg_start_rx(const struct usb_instance* instance, union usb_endpoint_number ep, void* buf, int size)
94
        DIEPCTL3 = (DIEPCTL3 & ~0x00008000) | 0x10000000;
94
{
95
        DOEPCTL4 = (DOEPCTL4 & ~0x00008000) | 0x10000000;
95
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
96
    }
96
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
97
    DAINTMSK = 0xFFFFFFFF;  /* Enable interrupts on all EPs */
97
 
98
}
98
    // Find the appropriate set of endpoint registers
99
 
99
    volatile struct synopsysotg_outepregs* regs = &data->core->outep_regs[ep.number];
100
int usb_drv_request_endpoint(int type, int dir)
100
    // Calculate number of packets (if size == 0 an empty packet will be sent)
101
{
101
    int maxpacket = regs->doepctl.b.mps;
102
    size_t ep;
102
    int packets = (size + maxpacket - 1) / maxpacket;
103
    int ret = -1;
103
    if (!packets) packets = 1;
104
 
104
 
105
    if (dir == USB_DIR_IN) ep = 1;
105
    // Set up data destination
106
    else ep = 2;
106
    if (data->use_dma) regs->doepdma = buf;
107
 
107
    else state->endpoints[ep.number].rxaddr = (uint32_t*)buf;
108
    while (ep < 5)
108
    union synopsysotg_depxfrsiz deptsiz = { .b = { .pktcnt = packets, .xfersize = size } };
109
    {
109
    regs->doeptsiz = deptsiz;
110
        if (!endpoints[ep].active)
110
 
111
        {
111
    // Flush CPU cache if necessary
112
            endpoints[ep].active = true;
112
    if (data->use_dma) invalidate_dcache(buf, size);
113
            ret = ep | dir;
113
 
114
            uint32_t newbits = (type << 18) | 0x10000000;
114
    // Enable the endpoint
115
            if (dir) DIEPCTL(ep) = (DIEPCTL(ep) & ~0x000C0000) | newbits;
115
    union synopsysotg_depctl depctl = regs->doepctl;
116
            else DOEPCTL(ep) = (DOEPCTL(ep) & ~0x000C0000) | newbits;
116
    depctl.b.epena = 1;
117
            break;
117
    depctl.b.cnak = 1;
118
        }
118
    regs->doepctl = depctl;
119
        ep += 2;
119
}
120
    }
120
 
121
 
121
void synopsysotg_start_tx(const struct usb_instance* instance, union usb_endpoint_number ep, const void* buf, int size)
122
    return ret;
122
{
123
}
123
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
124
 
124
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
125
void usb_drv_release_endpoint(int ep)
125
 
126
{
126
    // Find the appropriate set of endpoint registers
127
    ep = ep & 0x7f;
127
    volatile struct synopsysotg_inepregs* regs = &data->core->inep_regs[ep.number];
128
 
128
    // Calculate number of packets (if size == 0 an empty packet will be sent)
129
    if (ep < 1 || ep > USB_NUM_ENDPOINTS) return;
129
    int maxpacket = regs->diepctl.b.mps;
130
 
130
    int packets = (size + maxpacket - 1) / maxpacket;
131
    endpoints[ep].active = false;
131
    if (!packets) packets = 1;
132
}
132
 
133
 
133
    // Set up data source
134
static void usb_reset(void)
134
    if (data->use_dma) regs->diepdma = buf;
135
{
135
    else state->endpoints[ep.number].txaddr = (uint32_t*)buf;
136
    DCTL = 0x802;  /* Soft Disconnect */
136
    union synopsysotg_depxfrsiz deptsiz = { .b = { .pktcnt = packets, .xfersize = size } };
137
 
137
    regs->dieptsiz = deptsiz;
138
    OPHYPWR = 0;  /* PHY: Power up */
138
 
139
    udelay(10);
139
    // Flush CPU cache if necessary
140
    OPHYUNK1 = 1;
140
    if (data->use_dma) clean_dcache(buf, size);
141
    OPHYUNK2 = 0xE3F;
141
 
142
    ORSTCON = 1;  /* PHY: Assert Software Reset */
142
    // Enable the endpoint
143
    udelay(10);
143
    union synopsysotg_depctl depctl = regs->diepctl;
144
    ORSTCON = 0;  /* PHY: Deassert Software Reset */
144
    depctl.b.epena = 1;
145
    udelay(10);
145
    depctl.b.cnak = 1;
146
    OPHYUNK3 = 0x600;
146
    regs->diepctl = depctl;
147
    OPHYCLK = SYNOPSYSOTG_CLOCK;
147
 
148
    sleep(400);
148
    // Start pushing data into the FIFO (must be done after enabling the endpoint)
149
 
149
    if (size && !data->use_dma)
150
    GRSTCTL = 1;  /* OTG: Assert Software Reset */
150
    {
151
    while (GRSTCTL & 1);  /* Wait for OTG to ack reset */
151
        if (data->shared_txfifo) synopsysotg_try_push(instance, ep.number);
152
    while (!(GRSTCTL & 0x80000000));  /* Wait for OTG AHB master idle */
152
        else data->core->dregs.diepempmsk.ep.in |= (1 << ep.number);
153
 
153
    }
154
    GRXFSIZ = 0x00000200;  /* RX FIFO: 512 bytes */
154
}
155
    GNPTXFSIZ = 0x02000200;  /* Non-periodic TX FIFO: 512 bytes */
155
 
156
    GAHBCFG = SYNOPSYSOTG_AHBCFG;
156
int synopsysotg_get_stall(const struct usb_instance* instance, union usb_endpoint_number ep)
157
    GUSBCFG = 0x1408;  /* OTG: 16bit PHY and some reserved bits */
157
{
158
 
158
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
159
    DCFG = 4;  /* Address 0 */
159
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
160
    DCTL = 0x800;  /* Soft Reconnect */
160
        return !!data->core->inep_regs[ep.number].diepctl.b.stall;
161
    DIEPMSK = 0x0D;  /* IN EP interrupt mask */
161
    return !!data->core->outep_regs[ep.number].doepctl.b.stall;
162
    DOEPMSK = 0x0D;  /* IN EP interrupt mask */
162
}
163
    DAINTMSK = 0xFFFFFFFF;  /* Enable interrupts on all endpoints */
163
 
164
    GINTMSK = 0xC3000;  /* Interrupt mask: IN event, OUT event, bus reset */
164
void synopsysotg_set_stall(const struct usb_instance* instance, union usb_endpoint_number ep, int stall)
165
 
165
{
166
    reset_endpoints(1);
166
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
167
}
167
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
168
 
168
    {
169
/* IRQ handler */
169
        data->core->inep_regs[ep.number].diepctl.b.stall = !!stall;
170
void INT_USB_FUNC(void)
170
        if (!stall) data->core->inep_regs[ep.number].diepctl.b.setd0pid = true;
171
{
171
    }
172
    int i;
172
    else
173
    uint32_t ints = GINTSTS;
173
    {
174
    uint32_t epints;
174
        data->core->outep_regs[ep.number].doepctl.b.stall = !!stall;
175
    if (ints & 0x1000)  /* bus reset */
175
        if (!stall) data->core->outep_regs[ep.number].doepctl.b.setd0pid = true;
176
    {
176
    }
177
        DCFG = 4;  /* Address 0 */
177
 
178
        reset_endpoints(1);
178
}
179
        usb_handle_bus_reset();
179
 
180
    }
180
void synopsysotg_set_address(const struct usb_instance* instance, uint8_t address)
181
 
181
{
182
    if (ints & 0x2000)  /* enumeration done, we now know the speed */
182
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
183
    {
183
    data->core->dregs.dcfg.b.devaddr = address;
184
        /* Set up the maximum packet sizes accordingly */
184
}
185
        uint32_t maxpacket = usb_drv_port_speed() ? 512 : 64;
185
 
186
        DIEPCTL1 = (DIEPCTL1 & ~0x000003FF) | maxpacket;
186
void synopsysotg_unconfigure_ep(const struct usb_instance* instance, union usb_endpoint_number ep)
187
        DOEPCTL2 = (DOEPCTL2 & ~0x000003FF) | maxpacket;
187
{
188
        DIEPCTL3 = (DIEPCTL3 & ~0x000003FF) | maxpacket;
188
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
189
        DOEPCTL4 = (DOEPCTL4 & ~0x000003FF) | maxpacket;
189
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
190
    }
190
    {
191
 
191
        // Kill any outstanding IN transfers
192
    if (ints & 0x40000)  /* IN EP event */
192
        synopsysotg_flush_in_endpoint(instance, ep.number);
193
        for (i = 0; i < 4; i += i + 1)  // 0, 1, 3
193
        // Mask interrupts for this endpoint
194
            if (epints = DIEPINT(i))
194
        data->core->dregs.daintmsk.ep.in &= ~(1 << ep.number);
195
            {
195
    }
196
                if (epints & 1)  /* Transfer completed */
196
    else
197
                {
197
    {
198
                    int bytes = endpoints[i].size - (DIEPTSIZ(i) & 0x3FFFF);
198
        // Kill any outstanding OUT transfers
199
                    if (endpoints[i].busy)
199
        synopsysotg_flush_out_endpoint(instance, ep.number);
200
                    {
200
        // Mask interrupts for this endpoint
201
                        endpoints[i].busy = false;
201
        data->core->dregs.daintmsk.ep.out &= ~(1 << ep.number);
202
                        endpoints[i].rc = 0;
202
    }
203
                        endpoints[i].done = true;
203
}
204
                        usb_handle_transfer_complete(i, USB_DIR_IN, 0, bytes);
204
 
205
                        wakeup_signal(&endpoints[i].complete);
205
void synopsysotg_configure_ep(const struct usb_instance* instance, union usb_endpoint_number ep,
206
                    }
206
                              enum usb_endpoint_type type, int maxpacket)
207
                }
207
{
208
                if (epints & 4)  /* AHB error */
208
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
209
                    panicf(PANIC_FATAL, "USB: AHB error on IN EP%d", i);
209
 
210
                if (epints & 8)  /* Timeout */
210
    // Write the new configuration and unmask interrupts for the endpoint.
211
                {
211
    // Reset data toggle to DATA0, as required by the USB specification.
212
                    if (endpoints[i].busy)
212
    int txfifo = data->shared_txfifo ? 0 : ep.number;
213
                    {
213
    union synopsysotg_depctl depctl = { .b = { .usbactep = 1, .eptype = type, .mps = maxpacket,
214
                        endpoints[i].busy = false;
214
                                               .txfnum = txfifo, .setd0pid = 1, .nextep = (ep.number + 1) & 0xf } };
215
                        endpoints[i].rc = 1;
215
    if (ep.direction == USB_ENDPOINT_DIRECTION_IN)
216
                        endpoints[i].done = true;
216
    {
217
                        wakeup_signal(&endpoints[i].complete);
217
        data->core->inep_regs[ep.number].diepctl = depctl;
218
                    }
218
        data->core->dregs.daintmsk.ep.in |= (1 << ep.number);
219
                }
219
    }
220
                DIEPINT(i) = epints;
220
    else
221
            }
221
    {
222
 
222
        data->core->outep_regs[ep.number].doepctl = depctl;
223
    if (ints & 0x80000)  /* OUT EP event */
223
        data->core->dregs.daintmsk.ep.out |= (1 << ep.number);
224
        for (i = 0; i < 5; i += 2)  // 0, 2, 4
224
    }
225
            if (epints = DOEPINT(i))
225
}
226
            {
226
 
227
                if (epints & 1)  /* Transfer completed */
227
void synopsysotg_ep0_start_rx(const struct usb_instance* instance, int non_setup)
228
                {
228
{
229
                    int bytes = endpoints[i].size - (DOEPTSIZ(i) & 0x3FFFF);
229
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
230
                    if (endpoints[i].busy)
230
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
231
                    {
231
 
232
                        endpoints[i].busy = false;
232
    // Set up data destination
233
                        endpoints[i].rc = 0;
233
    if (data->use_dma) data->core->outep_regs[0].doepdma = instance->buffer;
234
                        endpoints[i].done = true;
234
    else state->endpoints[0].rxaddr = (uint32_t*)instance->buffer;
235
                        usb_handle_transfer_complete(i, USB_DIR_OUT, 0, bytes);
235
    union synopsysotg_dep0xfrsiz deptsiz = { .b = { .supcnt = 3, .pktcnt = !!non_setup, .xfersize = 64 } };
236
                        wakeup_signal(&endpoints[i].complete);
236
    data->core->outep_regs[0].doeptsiz.d32 = deptsiz.d32;
237
                    }
237
 
238
                }
238
    // Flush CPU cache if necessary
239
                if (epints & 4)  /* AHB error */
239
    if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
240
                    panicf(PANIC_FATAL, "USB: AHB error on OUT EP%d", i);
240
 
241
                if (epints & 8)  /* SETUP phase done */
241
    // Enable the endpoint
242
                {
242
    union synopsysotg_depctl depctl = data->core->outep_regs[0].doepctl;
243
                    invalidate_dcache();
243
    depctl.b.epena = 1;
244
                    if (i == 0) usb_handle_control_request(&ctrlreq);
244
    depctl.b.cnak = non_setup;
245
                    else panicf(PANIC_FATAL, "USB: SETUP done on OUT EP%d!?", i);
245
    data->core->outep_regs[0].doepctl = depctl;
246
                }
246
}
247
                /* Make sure EP0 OUT is set up to accept the next request */
247
 
248
                if (!i)
248
void synopsysotg_ep0_start_tx(const struct usb_instance* instance, const void* buf, int len)
249
                {
249
{
250
                    DOEPTSIZ0 = 0x20080040;
250
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
251
                    DOEPDMA0 = &ctrlreq;
251
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
252
                    DOEPCTL0 |= 0x84000000;
252
 
253
                }
253
    if (len)
254
                DOEPINT(i) = epints;
254
    {
255
            }
255
        // Set up data source
256
 
256
        if (data->use_dma) data->core->inep_regs[0].diepdma = buf;
257
    GINTSTS = ints;
257
        else state->endpoints[0].txaddr = buf;
258
}
258
        union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = (len + 63) >> 6, .xfersize = len } };
259
 
259
        data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
260
void usb_drv_set_address(int address)
260
    }
261
{
261
    else
262
    DCFG = (DCFG & ~0x7F0) | (address << 4);
262
    {
263
}
263
        // Set up the IN pipe for a zero-length packet
264
 
264
        union synopsysotg_dep0xfrsiz deptsiz = { .b = { .pktcnt = 1 } };
265
static void ep_send(int ep, const void *ptr, int length)
265
        data->core->inep_regs[0].dieptsiz.d32 = deptsiz.d32;
266
{
266
    }
267
    endpoints[ep].busy = true;
267
 
268
    endpoints[ep].size = length;
268
    // Flush CPU cache if necessary
269
    DIEPCTL(ep) |= 0x8000;  /* EPx OUT ACTIVE */
269
    if (data->use_dma) clean_dcache(buf, len);
270
    int blocksize = usb_drv_port_speed() ? 512 : 64;
270
 
271
    int packets = (length + blocksize - 1) / blocksize;
271
    // Enable the endpoint
272
    if (!length)
272
    union synopsysotg_depctl depctl = data->core->inep_regs[0].diepctl;
273
    {
273
    depctl.b.epena = 1;
274
        DIEPTSIZ(ep) = 1 << 19;  /* one empty packet */
274
    depctl.b.cnak = 1;
275
        DIEPDMA(ep) = NULL;  /* dummy address */
275
    data->core->inep_regs[0].diepctl = depctl;
276
    }
276
 
277
    else
277
    // Start pushing data into the FIFO (must be done after enabling the endpoint)
278
    {
278
    if (len && !data->use_dma)
279
        DIEPTSIZ(ep) = length | (packets << 19);
279
    {
280
        DIEPDMA(ep) = ptr;
280
        if (data->shared_txfifo) synopsysotg_try_push(instance, 0);
281
    }
281
        else data->core->dregs.diepempmsk.ep.in |= 1;
282
    clean_dcache();
282
    }
283
    DIEPCTL(ep) |= 0x84000000;  /* EPx OUT ENABLE CLEARNAK */
283
}
284
}
284
 
285
 
285
static void synopsysotg_ep0_init(const struct usb_instance* instance)
286
static void ep_recv(int ep, void *ptr, int length)
286
{
287
{
287
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
288
    endpoints[ep].busy = true;
288
 
289
    endpoints[ep].size = length;
289
    // Make sure both EP0 pipes are active.
290
    DOEPCTL(ep) &= ~0x20000;  /* EPx UNSTALL */
290
    // (The hardware should take care of that, but who knows...)
291
    DOEPCTL(ep) |= 0x8000;  /* EPx OUT ACTIVE */
291
    union synopsysotg_depctl depctl = { .b = { .usbactep = 1, .nextep = data->core->inep_regs[0].diepctl.b.nextep } };
292
    int blocksize = usb_drv_port_speed() ? 512 : 64;
292
    data->core->outep_regs[0].doepctl = depctl;
293
    int packets = (length + blocksize - 1) / blocksize;
293
    data->core->inep_regs[0].diepctl = depctl;
294
    if (!length)
294
}
295
    {
295
 
296
        DOEPTSIZ(ep) = 1 << 19;  /* one empty packet */
296
void synopsysotg_irq(const struct usb_instance* instance)
297
        DOEPDMA(ep) = NULL;  /* dummy address */
297
{
298
    }
298
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
299
    else
299
    struct synopsysotg_state* state = (struct synopsysotg_state*)instance->driver_state;
300
    {
300
 
301
        DOEPTSIZ(ep) = length | (packets << 19);
301
    union synopsysotg_gintsts gintsts = data->core->gregs.gintsts;
302
        DOEPDMA(ep) = ptr;
302
 
303
    }
303
    if (gintsts.b.usbreset)
304
    invalidate_dcache();
304
    {
305
    DOEPCTL(ep) |= 0x84000000;  /* EPx OUT ENABLE CLEARNAK */
305
        data->core->dregs.dcfg.b.devaddr = 0;
306
}
306
        usb_handle_bus_reset(instance, 0);
307
 
307
    }
308
int usb_drv_send(int endpoint, const void *ptr, int length)
308
 
309
{
309
    if (gintsts.b.enumdone)
310
    endpoint &= 0x7f;
310
    {
311
    endpoints[endpoint].done = false;
311
        usb_handle_bus_reset(instance, data->core->dregs.dsts.b.enumspd == 0);
312
    ep_send(endpoint, ptr, length);
312
        synopsysotg_ep0_init(instance);
313
    while (!endpoints[endpoint].done && endpoints[endpoint].busy)
313
    }
314
        wakeup_wait(&endpoints[endpoint].complete, TIMEOUT_BLOCK);
314
 
315
    return endpoints[endpoint].rc;
315
    if (gintsts.b.rxstsqlvl && !data->use_dma)
316
}
316
    {
317
 
317
        // Device to memory part of the "software DMA" implementation, used to receive data if use_dma == 0.
318
int usb_drv_send_nonblocking(int endpoint, const void *ptr, int length)
318
        // Handle one packet at a time, the IRQ will re-trigger if there's something left.
319
{
319
        union synopsysotg_grxfsts rxsts = data->core->gregs.grxstsp;
320
    ep_send(endpoint & 0x7f, ptr, length);
320
        int ep = rxsts.b.chnum;
321
    return 0;
321
        int words = (rxsts.b.bcnt + 3) >> 2;
322
}
322
        while (words--) *state->endpoints[ep].rxaddr++ = data->core->dfifo[0][0];
323
 
323
    }
324
int usb_drv_recv(int endpoint, void* ptr, int length)
324
 
325
{
325
    if (gintsts.b.nptxfempty && data->core->gregs.gintmsk.b.nptxfempty)
326
    ep_recv(endpoint & 0x7f, ptr, length);
326
    {
327
    return 0;
327
        // Old style, "shared TX FIFO" memory to device part of the "software DMA" implementation,
328
}
328
        // used to send data if use_dma == 0 and the device doesn't support one non-periodic TX FIFO per endpoint.
329
 
329
 
330
void usb_drv_cancel_all_transfers(void)
330
        // First disable the IRQ, it will be re-enabled later if there is anything left to be done.
331
{
331
        data->core->gregs.gintmsk.b.nptxfempty = false;
332
    uint32_t mode = enter_critical_section();
332
 
333
    reset_endpoints(0);
333
        // Check all endpoints for anything to be transmitted
334
    leave_critical_section(mode);
334
        int ep;
335
}
335
        for (ep = 0; ep < 16; ep++) synopsysotg_try_push(instance, ep);
336
 
336
    }
337
bool usb_drv_stalled(int endpoint, bool in)
337
 
338
{
338
    if (gintsts.b.inepintr)
339
    if (in) return DIEPCTL(endpoint) & 0x00200000 ? true : false;
339
    {
340
    else return DOEPCTL(endpoint) & 0x00200000 ? true : false;
340
        union synopsysotg_daint daint = data->core->dregs.daint;
341
}
341
        int ep;
342
 
342
        for (ep = 0; ep < 16; ep++)
343
void usb_drv_stall(int endpoint, bool stall, bool in)
343
            if (daint.ep.in & (1 << ep))
344
{
344
            {
345
    if (in)
345
                union synopsysotg_diepintn epints = data->core->inep_regs[ep].diepint;
346
    {
346
                if (epints.b.emptyintr)
347
        if (stall) DIEPCTL(endpoint) |= 0x00200000;
347
                {
348
        else DIEPCTL(endpoint) &= ~0x00200000;
348
                    // Memory to device part of the "software DMA" implementation, used to transmit data if use_dma == 0.
349
    }
349
                    union synopsysotg_depxfrsiz deptsiz = data->core->inep_regs[ep].dieptsiz;
350
    else
350
                    if (!deptsiz.b.xfersize) data->core->dregs.diepempmsk.ep.in &= ~(1 << ep);
351
    {
351
                    else
352
        if (stall) DOEPCTL(endpoint) |= 0x00200000;
352
                    {
353
        else DOEPCTL(endpoint) &= ~0x00200000;
353
                        // Push data into the TX FIFO until we don't have anything left or the FIFO would overflow.
354
    }
354
                        int left = (deptsiz.b.xfersize + 3) >> 2;
355
}
355
                        while (left)
356
 
356
                        {
357
void usb_drv_power_up(void)
357
                            int words = data->core->inep_regs[ep].dtxfsts.b.txfspcavail;
358
{
358
                            if (words > left) words = left;
359
    /* Enable USB clock */
359
                            if (!words) break;
360
    clockgate_enable(CLOCKGATE_USB_1, true);
360
                            left -= words;
361
    clockgate_enable(CLOCKGATE_USB_2, true);
361
                            while (words--) data->core->dfifo[ep][0] = *state->endpoints[ep].txaddr++;
362
    PCGCCTL = 0;
362
                        }
363
 
363
                    }
364
    /* reset the beast */
364
                }
365
    usb_reset();
365
                union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_IN, .number = ep };
366
}
366
                int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
367
 
367
                if (epints.b.timeout) usb_handle_timeout(instance, epnum, bytesleft);
368
void usb_drv_power_down(void)
368
                if (epints.b.xfercompl) usb_handle_xfer_complete(instance, epnum, bytesleft);
369
{
369
                data->core->inep_regs[ep].diepint = epints;
370
    DCTL = 0x802;  /* Soft Disconnect */
370
            }
371
 
371
    }
372
    OPHYPWR = 0xF;  /* PHY: Power down */
372
 
373
    udelay(10);
373
    if (gintsts.b.outepintr)
374
    ORSTCON = 7;  /* Put the PHY into reset (needed to get current down) */
374
    {
375
    udelay(10);
375
        union synopsysotg_daint daint = data->core->dregs.daint;
376
    PCGCCTL = 1;  /* Shut down PHY clock */
376
        int ep;
377
    
377
        for (ep = 0; ep < 16; ep++)
378
    clockgate_enable(CLOCKGATE_USB_1, false);
378
            if (daint.ep.out & (1 << ep))
379
    clockgate_enable(CLOCKGATE_USB_2, false);
379
            {
380
}
380
                union synopsysotg_doepintn epints = data->core->outep_regs[ep].doepint;
381
 
381
                union usb_endpoint_number epnum = { .direction = USB_ENDPOINT_DIRECTION_OUT, .number = ep };
382
void usb_check_vbus(void* arg0, void* arg1, void* arg2, void* arg3)
382
                if (epints.b.setup)
383
{
383
                {
384
    bool oldstate = false;
384
                    if (data->use_dma) invalidate_dcache(instance->buffer, sizeof(instance->buffer));
385
    while (true)
385
                    synopsysotg_flush_in_endpoint(instance, ep);
386
    {
386
                    usb_handle_setup_received(instance, epnum);
387
        sleep(200000);
387
                }
388
        bool newstate = vbus_state();
388
                else if (epints.b.xfercompl)
389
        if (oldstate != newstate)
389
                {
390
        {
390
                    int bytesleft = data->core->inep_regs[ep].dieptsiz.b.xfersize;
391
            if (newstate) usb_drv_power_up();
391
                    usb_handle_xfer_complete(instance, epnum, bytesleft);
392
            else usb_drv_power_down();
392
                }
393
            oldstate = newstate;
393
                data->core->outep_regs[ep].doepint = epints;
394
        }
394
            }
395
    }
395
    }
396
}
396
 
397
 
397
    data->core->gregs.gintsts = gintsts;
398
void usb_drv_init(void)
398
}
399
{
399
 
400
    unsigned int i;
400
void synopsysotg_init(const struct usb_instance* instance)
401
    for (i = 0; i < sizeof(endpoints)/sizeof(struct ep_type); i++)
401
{
402
        wakeup_init(&endpoints[i].complete);
402
    int i;
403
 
403
 
404
    /* Enable USB clock */
404
    const struct synopsysotg_config* data = (const struct synopsysotg_config*)instance->driver_config;
405
    clockgate_enable(CLOCKGATE_USB_1, true);
405
 
406
    clockgate_enable(CLOCKGATE_USB_2, true);
406
    // Disable IRQ during setup
407
    PCGCCTL = 0;
407
    synopsysotg_target_disable_irq(instance);
408
 
408
 
409
    /* unmask irq */
409
    // Enable OTG clocks
410
    interrupt_enable(IRQ_USB_FUNC, true);
410
    synopsysotg_target_enable_clocks(instance);
411
 
411
 
412
    thread_create(&synopsysotg_thread_handle, "synopsysotg", usb_check_vbus,
412
    // Enable PHY clocks
413
                  synopsysotg_stack, sizeof(synopsysotg_stack), OS_THREAD, 63, true,
413
    union synopsysotg_pcgcctl pcgcctl = { .b = {} };
414
                  NULL, NULL, NULL, NULL);
414
    data->core->pcgcctl = pcgcctl;
415
 
415
 
416
    usb_drv_power_down();
416
    // Configure PHY type (must be done before reset)
417
}
417
    union synopsysotg_gccfg gccfg = { .b = { .disablevbussensing = 1, .pwdn = 0 } };
418
 
418
    data->core->gregs.gccfg = gccfg;
419
void usb_drv_exit(void)
419
    union synopsysotg_gusbcfg gusbcfg = { .b = { .force_dev = 1, .usbtrdtim = SYNOPSYSOTG_TURNAROUND } };
420
{
420
    if (data->phy_16bit) gusbcfg.b.phyif = 1;
421
    usb_drv_power_down();
421
    else if (data->phy_ulpi) gusbcfg.b.ulpi_utmi_sel = 1;
422
}
422
    else gusbcfg.b.physel  = 1;
423
 
423
    data->core->gregs.gusbcfg = gusbcfg;
424
int usb_drv_get_max_out_size()
424
 
425
{
425
    // Reset the whole USB core
426
    return usb_drv_port_speed() ? 262144 : 32768;
426
    union synopsysotg_grstctl grstctl = { .b = { .csftrst = 1 } };
427
}
427
    udelay(100);
428
 
428
    while (!data->core->gregs.grstctl.b.ahbidle);
429
int usb_drv_get_max_in_size()
429
    data->core->gregs.grstctl = grstctl;
430
{
430
    while (data->core->gregs.grstctl.b.csftrst);
431
    return usb_drv_port_speed() ? 262144 : 32768;
431
    while (!data->core->gregs.grstctl.b.ahbidle);
432
}
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