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