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