Subversion Repositories freemyipod

Rev

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