Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
15 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
6
//    This file is part of emBIOS.
7
//
8
//    emBIOS is free software: you can redistribute it and/or
9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
13
//    emBIOS is distributed in the hope that it will be useful,
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
19
//    with emBIOS.  If not, see <http://www.gnu.org/licenses/>.
20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "mmu.h"
26
#include "panic.h"
27
#include "usbdrv.h"
28
#include "thread.h"
29
#include "timer.h"
30
#include "usb.h"
31
#include "usb_ch9.h"
32
#include "synopsysotg.h"
58 theseven 33
#include "util.h"
85 theseven 34
#include "interrupt.h"
15 theseven 35
 
36
 
37
struct ep_type
38
{
39
    bool active;
40
    bool busy;
41
    bool done;
42
    int rc;
43
    int size;
44
    struct wakeup complete;
45
} ;
46
 
47
static struct ep_type endpoints[5];
48
static struct usb_ctrlrequest ctrlreq CACHEALIGN_ATTR;
49
 
50
int usb_drv_port_speed(void)
51
{
52
    return (DSTS & 2) == 0 ? 1 : 0;
53
}
54
 
66 theseven 55
static void reset_endpoints(int reinit)
15 theseven 56
{
57
    unsigned int i;
58
    for (i = 0; i < sizeof(endpoints)/sizeof(struct ep_type); i++)
59
    {
60
        if (reinit) endpoints[i].active = false;
61
        endpoints[i].busy = false;
62
        endpoints[i].rc = -1;
63
        endpoints[i].done = true;
64
        wakeup_signal(&endpoints[i].complete);
65
    }
66
    DIEPCTL0 = 0x8800;  /* EP0 IN ACTIVE NEXT=1 */
67
    DOEPCTL0 = 0x8000;  /* EP0 OUT ACTIVE */
68
    DOEPTSIZ0 = 0x20080040;  /* EP0 OUT Transfer Size:
69
                                64 Bytes, 1 Packet, 1 Setup Packet */
70
    DOEPDMA0 = (uint32_t)&ctrlreq;
71
    DOEPCTL0 |= 0x84000000;  /* EP0 OUT ENABLE CLEARNAK */
72
    if (reinit)
73
    {
74
        /* The size is getting set to zero, because we don't know
75
           whether we are Full Speed or High Speed at this stage */
76
        /* EP1 IN INACTIVE DATA0 SIZE=0 NEXT=3 */
77
        DIEPCTL1 = 0x10001800;
78
        /* EP2 OUT INACTIVE DATA0 SIZE=0 */
79
        DOEPCTL2 = 0x10000000;
80
        /* EP3 IN INACTIVE DATA0 SIZE=0 NEXT=0 */
81
        DIEPCTL3 = 0x10000000;
82
        /* EP4 OUT INACTIVE DATA0 SIZE=0 */
83
        DOEPCTL4 = 0x10000000;
84
    }
85
    else
86
    {
87
        /* INACTIVE DATA0 */
88
        DIEPCTL1 = (DIEPCTL1 & ~0x00008000) | 0x10000000;
89
        DOEPCTL2 = (DOEPCTL2 & ~0x00008000) | 0x10000000;
90
        DIEPCTL3 = (DIEPCTL3 & ~0x00008000) | 0x10000000;
91
        DOEPCTL4 = (DOEPCTL4 & ~0x00008000) | 0x10000000;
92
    }
93
    DAINTMSK = 0xFFFFFFFF;  /* Enable interrupts on all EPs */
94
}
95
 
96
int usb_drv_request_endpoint(int type, int dir)
97
{
98
    size_t ep;
99
    int ret = -1;
100
 
101
    if (dir == USB_DIR_IN) ep = 1;
102
    else ep = 2;
103
 
104
    while (ep < 5)
105
    {
106
        if (!endpoints[ep].active)
107
        {
108
            endpoints[ep].active = true;
109
            ret = ep | dir;
110
            uint32_t newbits = (type << 18) | 0x10000000;
111
            if (dir) DIEPCTL(ep) = (DIEPCTL(ep) & ~0x000C0000) | newbits;
112
            else DOEPCTL(ep) = (DOEPCTL(ep) & ~0x000C0000) | newbits;
113
            break;
114
        }
115
        ep += 2;
116
    }
117
 
118
    return ret;
119
}
120
 
121
void usb_drv_release_endpoint(int ep)
122
{
123
    ep = ep & 0x7f;
124
 
125
    if (ep < 1 || ep > USB_NUM_ENDPOINTS) return;
126
 
127
    endpoints[ep].active = false;
128
}
129
 
130
static void usb_reset(void)
131
{
132
    volatile int i;
133
 
134
    DCTL = 0x802;  /* Soft Disconnect */
135
 
136
    OPHYPWR = 0;  /* PHY: Power up */
85 theseven 137
    OPHYUNK1 = 1;
15 theseven 138
    OPHYUNK2 = 0xE3F;
85 theseven 139
    OPHYCLK = SYNOPSYSOTG_CLOCK;
15 theseven 140
    ORSTCON = 1;  /* PHY: Assert Software Reset */
141
    udelay(10);
142
    ORSTCON = 0;  /* PHY: Deassert Software Reset */
143
 
144
    GRSTCTL = 1;  /* OTG: Assert Software Reset */
145
    while (GRSTCTL & 1);  /* Wait for OTG to ack reset */
146
    while (!(GRSTCTL & 0x80000000));  /* Wait for OTG AHB master idle */
147
 
148
    GRXFSIZ = 0x00000200;  /* RX FIFO: 512 bytes */
149
    GNPTXFSIZ = 0x02000200;  /* Non-periodic TX FIFO: 512 bytes */
85 theseven 150
    GAHBCFG = SYNOPSYSOTG_AHBCFG;
15 theseven 151
    GUSBCFG = 0x1408;  /* OTG: 16bit PHY and some reserved bits */
152
 
153
    DCFG = 4;  /* Address 0 */
154
    DCTL = 0x800;  /* Soft Reconnect */
155
    DIEPMSK = 0x0D;  /* IN EP interrupt mask */
156
    DOEPMSK = 0x0D;  /* IN EP interrupt mask */
157
    DAINTMSK = 0xFFFFFFFF;  /* Enable interrupts on all endpoints */
158
    GINTMSK = 0xC3000;  /* Interrupt mask: IN event, OUT event, bus reset */
159
 
160
    reset_endpoints(1);
161
}
162
 
163
/* IRQ handler */
164
void INT_USB_FUNC(void)
165
{
166
    int i;
167
    uint32_t ints = GINTSTS;
168
    uint32_t epints;
169
    if (ints & 0x1000)  /* bus reset */
170
    {
171
        DCFG = 4;  /* Address 0 */
172
        reset_endpoints(1);
173
        usb_handle_bus_reset();
174
    }
175
 
176
    if (ints & 0x2000)  /* enumeration done, we now know the speed */
177
    {
178
        /* Set up the maximum packet sizes accordingly */
179
        uint32_t maxpacket = usb_drv_port_speed() ? 512 : 64;
180
        DIEPCTL1 = (DIEPCTL1 & ~0x000003FF) | maxpacket;
181
        DOEPCTL2 = (DOEPCTL2 & ~0x000003FF) | maxpacket;
182
        DIEPCTL3 = (DIEPCTL3 & ~0x000003FF) | maxpacket;
183
        DOEPCTL4 = (DOEPCTL4 & ~0x000003FF) | maxpacket;
184
    }
185
 
186
    if (ints & 0x40000)  /* IN EP event */
187
        for (i = 0; i < 4; i += i + 1)  // 0, 1, 3
188
            if (epints = DIEPINT(i))
189
            {
190
                if (epints & 1)  /* Transfer completed */
191
                {
192
                    invalidate_dcache();
193
                    int bytes = endpoints[i].size - (DIEPTSIZ(i) & 0x3FFFF);
194
                    if (endpoints[i].busy)
195
                    {
196
                        endpoints[i].busy = false;
197
                        endpoints[i].rc = 0;
198
                        endpoints[i].done = true;
199
                        usb_handle_transfer_complete(i, USB_DIR_IN, 0, bytes);
200
                        wakeup_signal(&endpoints[i].complete);
201
                    }
202
                }
203
                if (epints & 4)  /* AHB error */
204
                    panicf(PANIC_FATAL, "USB: AHB error on IN EP%d", i);
205
                if (epints & 8)  /* Timeout */
206
                {
207
                    if (endpoints[i].busy)
208
                    {
209
                        endpoints[i].busy = false;
210
                        endpoints[i].rc = 1;
211
                        endpoints[i].done = true;
212
                        wakeup_signal(&endpoints[i].complete);
213
                    }
214
                }
215
                DIEPINT(i) = epints;
216
            }
217
 
218
    if (ints & 0x80000)  /* OUT EP event */
219
        for (i = 0; i < 5; i += 2)  // 0, 2, 4
220
            if (epints = DOEPINT(i))
221
            {
222
                if (epints & 1)  /* Transfer completed */
223
                {
224
                    invalidate_dcache();
225
                    int bytes = endpoints[i].size - (DOEPTSIZ(i) & 0x3FFFF);
226
                    if (endpoints[i].busy)
227
                    {
228
                        endpoints[i].busy = false;
229
                        endpoints[i].rc = 0;
230
                        endpoints[i].done = true;
231
                        usb_handle_transfer_complete(i, USB_DIR_OUT, 0, bytes);
232
                        wakeup_signal(&endpoints[i].complete);
233
                    }
234
                }
235
                if (epints & 4)  /* AHB error */
236
                    panicf(PANIC_FATAL, "USB: AHB error on OUT EP%d", i);
237
                if (epints & 8)  /* SETUP phase done */
238
                {
239
                    invalidate_dcache();
240
                    if (i == 0) usb_handle_control_request(&ctrlreq);
241
                    else panicf(PANIC_FATAL, "USB: SETUP done on OUT EP%d!?", i);
242
                }
243
                /* Make sure EP0 OUT is set up to accept the next request */
244
                if (!i)
245
                {
246
                    DOEPTSIZ0 = 0x20080040;
247
                    DOEPDMA0 = (uint32_t)&ctrlreq;
248
                    DOEPCTL0 |= 0x84000000;
249
                }
250
                DOEPINT(i) = epints;
251
            }
252
 
253
    GINTSTS = ints;
254
}
255
 
256
void usb_drv_set_address(int address)
257
{
258
    DCFG = (DCFG & ~0x7F0) | (address << 4);
259
}
260
 
66 theseven 261
static void ep_send(int ep, const void *ptr, int length)
15 theseven 262
{
263
    endpoints[ep].busy = true;
264
    endpoints[ep].size = length;
265
    DIEPCTL(ep) |= 0x8000;  /* EPx OUT ACTIVE */
266
    int blocksize = usb_drv_port_speed() ? 512 : 64;
267
    int packets = (length + blocksize - 1) / blocksize;
268
    if (!length)
269
    {
270
        DIEPTSIZ(ep) = 1 << 19;  /* one empty packet */
271
        DIEPDMA(ep) = 0x10000000;  /* dummy address */
272
    }
273
    else
274
    {
275
        DIEPTSIZ(ep) = length | (packets << 19);
276
        DIEPDMA(ep) = (uint32_t)ptr;
277
    }
278
    clean_dcache();
279
    DIEPCTL(ep) |= 0x84000000;  /* EPx OUT ENABLE CLEARNAK */
280
}
281
 
66 theseven 282
static void ep_recv(int ep, void *ptr, int length)
15 theseven 283
{
284
    endpoints[ep].busy = true;
285
    endpoints[ep].size = length;
286
    DOEPCTL(ep) &= ~0x20000;  /* EPx UNSTALL */
287
    DOEPCTL(ep) |= 0x8000;  /* EPx OUT ACTIVE */
288
    int blocksize = usb_drv_port_speed() ? 512 : 64;
289
    int packets = (length + blocksize - 1) / blocksize;
290
    if (!length)
291
    {
292
        DOEPTSIZ(ep) = 1 << 19;  /* one empty packet */
293
        DOEPDMA(ep) = 0x10000000;  /* dummy address */
294
    }
295
    else
296
    {
297
        DOEPTSIZ(ep) = length | (packets << 19);
298
        DOEPDMA(ep) = (uint32_t)ptr;
299
    }
300
    clean_dcache();
301
    DOEPCTL(ep) |= 0x84000000;  /* EPx OUT ENABLE CLEARNAK */
302
}
303
 
304
int usb_drv_send(int endpoint, const void *ptr, int length)
305
{
306
    endpoint &= 0x7f;
307
    endpoints[endpoint].done = false;
308
    ep_send(endpoint, ptr, length);
309
    while (!endpoints[endpoint].done && endpoints[endpoint].busy)
310
        wakeup_wait(&endpoints[endpoint].complete, TIMEOUT_BLOCK);
311
    return endpoints[endpoint].rc;
312
}
313
 
314
int usb_drv_send_nonblocking(int endpoint, const void *ptr, int length)
315
{
316
    ep_send(endpoint & 0x7f, ptr, length);
317
    return 0;
318
}
319
 
320
int usb_drv_recv(int endpoint, void* ptr, int length)
321
{
322
    ep_recv(endpoint & 0x7f, ptr, length);
323
    return 0;
324
}
325
 
326
void usb_drv_cancel_all_transfers(void)
327
{
328
    uint32_t mode = enter_critical_section();
329
    reset_endpoints(0);
330
    leave_critical_section(mode);
331
}
332
 
333
bool usb_drv_stalled(int endpoint, bool in)
334
{
335
    if (in) return DIEPCTL(endpoint) & 0x00200000 ? true : false;
336
    else return DOEPCTL(endpoint) & 0x00200000 ? true : false;
337
}
338
 
339
void usb_drv_stall(int endpoint, bool stall, bool in)
340
{
341
    if (in)
342
    {
343
        if (stall) DIEPCTL(endpoint) |= 0x00200000;
344
        else DIEPCTL(endpoint) &= ~0x00200000;
345
    }
346
    else
347
    {
348
        if (stall) DOEPCTL(endpoint) |= 0x00200000;
349
        else DOEPCTL(endpoint) &= ~0x00200000;
350
    }
351
}
352
 
353
void usb_drv_init(void)
354
{
355
    unsigned int i;
356
    for (i = 0; i < sizeof(endpoints)/sizeof(struct ep_type); i++)
357
        wakeup_init(&endpoints[i].complete);
358
 
359
    /* Enable USB clock */
360
    PWRCON &= ~0x4000;
361
    PWRCONEXT &= ~0x800;
362
    PCGCCTL = 0;
363
 
364
    /* unmask irq */
85 theseven 365
    interrupt_enable(IRQ_USB_FUNC, true);
15 theseven 366
 
367
    /* reset the beast */
368
    usb_reset();
369
}
28 theseven 370
 
371
int usb_drv_get_max_out_size()
372
{
373
    return usb_drv_port_speed() ? 262144 : 32768;
374
}
375
 
376
int usb_drv_get_max_in_size()
377
{
378
    return usb_drv_port_speed() ? 262144 : 32768;
379
}