summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/usb-drv-as3525.c
blob: 8a1abea74f123824ee25c06fdaae2598e96badff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright © 2009 Rafaël Carré
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include "usb.h"
#include "usb_drv.h"
#include "as3525.h"
#include "clock-target.h"
#include "ascodec.h"
#include "as3514.h"
#include <stdbool.h>
#include "panic.h"
//#define LOGF_ENABLE
#include "logf.h"


/* 4 input endpoints */
#define USB_IEP_CTRL(i)     *((volatile unsigned long*) USB_BASE + 0x0000 + (i*0x20))
#define USB_IEP_STS(i)      *((volatile unsigned long*) USB_BASE + 0x0004 + (i*0x20))
#define USB_IEP_TXFSIZE(i)  *((volatile unsigned long*) USB_BASE + 0x0008 + (i*0x20))
#define USB_IEP_MPS(i)      *((volatile unsigned long*) USB_BASE + 0x000C + (i*0x20))
#define USB_IEP_DESC_PTR(i) *((volatile unsigned long*) USB_BASE + 0x0014 + (i*0x20))
#define USB_IEP_STS_MASK(i) *((volatile unsigned long*) USB_BASE + 0x0018 + (i*0x20))

/* 4 output endpoints */
#define USB_OEP_CTRL(i)     *((volatile unsigned long*) USB_BASE + 0x0200 + (i*0x20))
#define USB_OEP_STS(i)      *((volatile unsigned long*) USB_BASE + 0x0204 + (i*0x20))
#define USB_OEP_RXFR(i)     *((volatile unsigned long*) USB_BASE + 0x0208 + (i*0x20))
#define USB_OEP_MPS(i)      *((volatile unsigned long*) USB_BASE + 0x020C + (i*0x20))
#define USB_OEP_SUP_PTR(i)  *((volatile unsigned long*) USB_BASE + 0x0210 + (i*0x20))
#define USB_OEP_DESC_PTR(i) *((volatile unsigned long*) USB_BASE + 0x0214 + (i*0x20))
#define USB_OEP_STS_MASK(i) *((volatile unsigned long*) USB_BASE + 0x0218 + (i*0x20))

#define USB_DEV_CFG             *((volatile unsigned long*) USB_BASE + 0x0400)
#define USB_DEV_CTRL            *((volatile unsigned long*) USB_BASE + 0x0404)
#define USB_DEV_STS             *((volatile unsigned long*) USB_BASE + 0x0408)
#define USB_DEV_INTR            *((volatile unsigned long*) USB_BASE + 0x040C)
#define USB_DEV_INTR_MASK       *((volatile unsigned long*) USB_BASE + 0x0410)
#define USB_DEV_EP_INTR         *((volatile unsigned long*) USB_BASE + 0x0414)
#define USB_DEV_EP_INTR_MASK    *((volatile unsigned long*) USB_BASE + 0x0418)

#define USB_PHY_EP0_INFO        *((volatile unsigned long*) USB_BASE + 0x0504)
#define USB_PHY_EP1_INFO        *((volatile unsigned long*) USB_BASE + 0x0508)
#define USB_PHY_EP2_INFO        *((volatile unsigned long*) USB_BASE + 0x050C)
#define USB_PHY_EP3_INFO        *((volatile unsigned long*) USB_BASE + 0x0510)
#define USB_PHY_EP4_INFO        *((volatile unsigned long*) USB_BASE + 0x0514)
#define USB_PHY_EP5_INFO        *((volatile unsigned long*) USB_BASE + 0x0518)

/* 4 channels */
#define USB_HOST_CH_SPLT(i)     *((volatile unsigned long*) USB_BASE + 0x1000 + (i*0x20))
#define USB_HOST_CH_STS(i)      *((volatile unsigned long*) USB_BASE + 0x1004 + (i*0x20))
#define USB_HOST_CH_TXFSIZE(i)  *((volatile unsigned long*) USB_BASE + 0x1008 + (i*0x20))
#define USB_HOST_CH_REQ(i)      *((volatile unsigned long*) USB_BASE + 0x100C + (i*0x20))
#define USB_HOST_CH_PER_INFO(i) *((volatile unsigned long*) USB_BASE + 0x1010 + (i*0x20))
#define USB_HOST_CH_DESC_PTR(i) *((volatile unsigned long*) USB_BASE + 0x1014 + (i*0x20))
#define USB_HOST_CH_STS_MASK(i) *((volatile unsigned long*) USB_BASE + 0x1018 + (i*0x20))

#define USB_HOST_CFG            *((volatile unsigned long*) USB_BASE + 0x1400)
#define USB_HOST_CTRL           *((volatile unsigned long*) USB_BASE + 0x1404)
#define USB_HOST_INTR           *((volatile unsigned long*) USB_BASE + 0x140C)
#define USB_HOST_INTR_MASK      *((volatile unsigned long*) USB_BASE + 0x1410)
#define USB_HOST_CH_INTR        *((volatile unsigned long*) USB_BASE + 0x1414)
#define USB_HOST_CH_INTR_MASK   *((volatile unsigned long*) USB_BASE + 0x1418)
#define USB_HOST_FRAME_INT      *((volatile unsigned long*) USB_BASE + 0x141C)
#define USB_HOST_FRAME_REM      *((volatile unsigned long*) USB_BASE + 0x1420)
#define USB_HOST_FRAME_NUM      *((volatile unsigned long*) USB_BASE + 0x1424)

#define USB_HOST_PORT0_CTRL_STS *((volatile unsigned long*) USB_BASE + 0x1500)

#define USB_OTG_CSR             *((volatile unsigned long*) USB_BASE + 0x2000)
#define USB_I2C_CSR             *((volatile unsigned long*) USB_BASE + 0x2004)
#define USB_GPIO_CSR            *((volatile unsigned long*) USB_BASE + 0x2008)
#define USB_SNPSID_CSR          *((volatile unsigned long*) USB_BASE + 0x200C)
#define USB_USERID_CSR          *((volatile unsigned long*) USB_BASE + 0x2010)
#define USB_USER_CONF1          *((volatile unsigned long*) USB_BASE + 0x2014)
#define USB_USER_CONF2          *((volatile unsigned long*) USB_BASE + 0x2018)
#define USB_USER_CONF3          *((volatile unsigned long*) USB_BASE + 0x201C)
#define USB_USER_CONF4          *((volatile unsigned long*) USB_BASE + 0x2020)
#define USB_USER_CONF5          *((volatile unsigned long*) USB_BASE + 0x2024)

struct usb_endpoint
{
    void *buf;
    unsigned int len;
    union
    {
        unsigned int sent;
        unsigned int received;
    };
    bool wait;
    bool busy;
};

static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2];

void usb_attach(void)
{
    usb_enable(true);
}

void usb_drv_init(void)
{
    int i;
    for(i = 0; i < USB_NUM_ENDPOINTS * 2; i++)
        endpoints[i].busy = false;

    ascodec_write(AS3514_CVDD_DCDC3, ascodec_read(AS3514_CVDD_DCDC3) | 1<<2);
    ascodec_write(AS3514_USB_UTIL, ascodec_read(AS3514_USB_UTIL) & ~(1<<4));

    /* PHY part */
    CGU_USB = 1<<5 /* enable */
        | (CLK_DIV(AS3525_PLLA_FREQ, 48000000) / 2) << 2
        | 1; /* source = PLLA */

    /* AHB part */
    CGU_PERI |= CGU_USB_CLOCK_ENABLE;

    USB_GPIO_CSR = 0x6180000;
    USB_DEV_CFG = (USB_DEV_CFG & ~3) | 1; /* full speed */
    USB_DEV_CTRL |= 0x400; /* soft disconnect */

    /* UVDD */
    ascodec_write(AS3514_USB_UTIL, ascodec_read(AS3514_USB_UTIL) | (1<<4));
    sleep(10); //msleep(100)

    USB_GPIO_CSR = 0x6180000;

    USB_GPIO_CSR |= 0x1C00000;
    sleep(1); //msleep(3)
    USB_GPIO_CSR |= 0x200000;
    sleep(1); //msleep(10)

    USB_DEV_CTRL |= 0x400; /* soft disconnect */

    USB_GPIO_CSR &= ~0x1C00000;
    sleep(1); //msleep(3)
    USB_GPIO_CSR &= ~0x200000;
    sleep(1); //msleep(10)
    USB_DEV_CTRL &= ~0x400; /* clear soft disconnect */

    /* note : this pin might be Clip specific */
    GPIOA_DIR |= (1<<6);
    GPIOA_PIN(6) = (1<<6);
    GPIOA_DIR &= ~(1<<6);   /* restore direction for usb_detect() */

#if 0 /* linux */
    USB_DEV_CFG |= (1<<17)  /* csr programming */
                |  (1<<3)   /* self powered */
                |  (1<<2);  /* remote wakeup */

    USB_DEV_CFG &= ~3; /* high speed */
#endif

    USB_IEP_CTRL(0) &= (3 << 4); /* control endpoint */
    USB_IEP_DESC_PTR(0) = 0;

    USB_OEP_CTRL(0) &= (3 << 4); /* control endpoint */
    USB_OEP_DESC_PTR(0) = 0;

    USB_DEV_INTR_MASK &= ~0xff;   /* unmask all flags */

    USB_DEV_EP_INTR_MASK &= ~((1<<0) | (1<<16));    /* ep 0 */

    VIC_INT_ENABLE |= INTERRUPT_USB;

    USB_IEP_CTRL(0) |= (1<<7); /* set NAK */
    USB_OEP_CTRL(0) |= (1<<7); /* set NAK */
}

void usb_drv_exit(void)
{
    USB_DEV_CTRL |= (1<<10); /* soft disconnect */
    VIC_INT_EN_CLEAR = INTERRUPT_USB;
    CGU_USB &= ~(1<<5);
    CGU_PERI &= ~CGU_USB_CLOCK_ENABLE;
    ascodec_write(AS3514_USB_UTIL, ascodec_read(AS3514_USB_UTIL) & ~(1<<4));
}

int usb_drv_port_speed(void)
{
    return (USB_DEV_CFG & 3) ? 0 : 1;
}

int usb_drv_request_endpoint(int type, int dir)
{
    (void) type;
    int i = dir == USB_DIR_IN ? 0 : 1;

    for(; i < USB_NUM_ENDPOINTS * 2; i += 2)
        if(!endpoints[i].busy)
        {
            endpoints[i].busy = true;
            i >>= 1;
            USB_DEV_EP_INTR_MASK &= ~((1<<i) | (1<<(16+i)));
            return i | dir;
        }

    return -1;
}

void usb_drv_release_endpoint(int ep)
{
    int i = (ep & 0x7f) * 2;
    if(ep & USB_DIR_OUT)
        i++;
    endpoints[i].busy = false;
    USB_DEV_EP_INTR_MASK |= (1<<ep) | (1<<(16+ep));
}

void usb_drv_cancel_all_transfers(void)
{
}

int usb_drv_recv(int ep, void *ptr, int len)
{
    (void)ep;(void)ptr;(void)len;
    if(ep >= 2)
        return -1;

    return -1;
}

int usb_drv_send(int ep, void *ptr, int len)
{
    (void)ep;(void)ptr;(void)len;
    if(ep >= 2)
        return -1;

    return -1;
}

int usb_drv_send_nonblocking(int ep, void *ptr, int len)
{
    /* TODO */
    return usb_drv_send(ep, ptr, len);
}

/* interrupt service routine */
void INT_USB(void)
{
    panicf("USB interrupt !");
}

/* (not essential? , not implemented in usb-tcc.c) */
void usb_drv_set_test_mode(int mode)
{
    (void)mode;
}

void usb_drv_set_address(int address)
{
    (void)address;
}

void usb_drv_stall(int ep, bool stall, bool in)
{
    (void)ep;(void)stall;(void)in;
}

bool usb_drv_stalled(int ep, bool in)
{
    (void)ep;(void)in;
    return true;
}