summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--utils/hwstub/stub/atj213x/usb_drv_atj213x.c307
1 files changed, 195 insertions, 112 deletions
diff --git a/utils/hwstub/stub/atj213x/usb_drv_atj213x.c b/utils/hwstub/stub/atj213x/usb_drv_atj213x.c
index ef66766527..fa545a767c 100644
--- a/utils/hwstub/stub/atj213x/usb_drv_atj213x.c
+++ b/utils/hwstub/stub/atj213x/usb_drv_atj213x.c
@@ -31,6 +31,17 @@
31volatile bool setup_data_valid = false; 31volatile bool setup_data_valid = false;
32volatile int udc_speed = USB_FULL_SPEED; 32volatile int udc_speed = USB_FULL_SPEED;
33 33
34struct endpoint_t
35{
36 void *buf;
37 int length;
38 bool zlp;
39 bool finished;
40};
41
42static volatile struct endpoint_t ep0in;
43static volatile struct endpoint_t ep0out;
44
34static void usb_copy_from(void *ptr, volatile void *reg, size_t sz) 45static void usb_copy_from(void *ptr, volatile void *reg, size_t sz)
35{ 46{
36 uint32_t *p = ptr; 47 uint32_t *p = ptr;
@@ -67,93 +78,70 @@ static void usb_copy_to(volatile void *reg, void *ptr, size_t sz)
67 *rp++ = *p++; 78 *rp++ = *p++;
68} 79}
69 80
70void INT_UDC(void) 81static void reset_all_fifos(void)
71{ 82{
72 /* get possible sources */ 83 /* reset all ep fifos */
73 unsigned int usbirq = OTG_USBIRQ;
74 unsigned int otgirq = OTG_OTGIRQ;
75#if 0
76 unsigned int usbeirq = OTG_USBEIRQ;
77 unsigned int epinirq = OTG_IN04IRQ;
78 unsigned int epoutirq = OTG_OUT04IRQ;
79#endif
80
81 /* HS, Reset, Setup */
82 if (usbirq)
83 {
84
85 if (usbirq & (1<<5))
86 {
87 /* HS irq */
88 udc_speed = USB_HIGH_SPEED;
89 }
90 else if (usbirq & (1<<4))
91 {
92 /* Reset */
93 udc_speed = USB_FULL_SPEED;
94
95 /* clear all pending irqs */
96 OTG_OUT04IRQ = 0xff;
97 OTG_IN04IRQ = 0xff;
98 }
99 else if (usbirq & (1<<0))
100 {
101 /* Setup data valid */
102 setup_data_valid = true;
103 }
104
105 /* clear irq flags */
106 OTG_USBIRQ = usbirq;
107 }
108 84
109#if 0 85 /* IN fifos */
110 if (epoutirq) 86 OTG_ENDPRST = 0x10;
111 { 87 OTG_ENDPRST = 0x70;
112 OTG_OUT04IRQ = epoutirq;
113 }
114
115 if (epinirq)
116 {
117 OTG_IN04IRQ = epinirq;
118 }
119#endif
120 88
121 if (otgirq) 89 /* OUT fifos */
122 { 90 OTG_ENDPRST = 0x00;
123 OTG_OTGIRQ = otgirq; 91 OTG_ENDPRST = 0x60;
124 } 92}
125 93
126 OTG_USBEIRQ = 0x50; 94static void cancel_all_transfers(void)
95{
96 ep0out.buf = NULL;
97 ep0out.length = 0;
98 ep0out.zlp = false;
99 ep0out.finished = true;
100
101 ep0in.buf = NULL;
102 ep0in.length = 0;
103 ep0in.zlp = false;
104 ep0in.finished = true;
127} 105}
128 106
129void usb_drv_init(void) 107void usb_drv_init(void)
130{ 108{
131 OTG_USBCS |= 0x40; /* soft disconnect */ 109 /* soft disconnect */
110 OTG_USBCS |= 0x40;
132 111
133 OTG_ENDPRST = 0x10; /* reset all ep fifos */ 112 cancel_all_transfers();
134 OTG_ENDPRST = 0x70; 113 reset_all_fifos();
135 OTG_ENDPRST = 0x00;
136 OTG_ENDPRST = 0x60;
137 114
138 OTG_USBIRQ = 0xff; /* clear all pending interrupts */ 115 /* clear all pending interrupts */
116 OTG_USBIRQ = 0xff;
139 OTG_OTGIRQ = 0xff; 117 OTG_OTGIRQ = 0xff;
140 OTG_IN04IRQ = 0xff; 118 OTG_IN04IRQ = 0xff;
141 OTG_OUT04IRQ = 0xff; 119 OTG_OUT04IRQ = 0xff;
142 OTG_USBEIRQ = 0x50; /* UDC ? with 0x40 there is irq storm */
143 120
144 OTG_USBIEN = (1<<5) | (1<<4) | (1<<0); /* HS, Reset, Setup_data */ 121 /* bit6 - USB wakeup
122 * bit4 - connect/disconnect
123 *
124 * with 0x40 here there is irq storm
125 */
126 OTG_USBEIRQ = 0x50;
127
128 /* HS, Reset, Setup_data */
129 OTG_USBIEN = (1<<5) | (1<<4) | (1<<0);
130
131 /* No OTG interrupts ? */
145 OTG_OTGIEN = 0; 132 OTG_OTGIEN = 0;
146 133
147 /* disable interrupts from ep0 */ 134 /* enable interrupts from ep0 */
148 OTG_IN04IEN = 0; 135 OTG_IN04IEN = 1;
149 OTG_OUT04IEN = 0; 136 OTG_OUT04IEN = 1;
150 137
151 /* unmask UDC interrupt in interrupt controller */ 138 /* unmask UDC interrupt in interrupt controller */
152 INTC_MSK = (1<<4); 139 INTC_MSK = (1<<4);
153 140
154 target_mdelay(100); 141 target_mdelay(100);
155 142
156 OTG_USBCS &= ~0x40; /* soft connect */ 143 /* soft connect */
144 OTG_USBCS &= ~0x40;
157} 145}
158 146
159int usb_drv_recv_setup(struct usb_ctrlrequest *req) 147int usb_drv_recv_setup(struct usb_ctrlrequest *req)
@@ -163,6 +151,7 @@ int usb_drv_recv_setup(struct usb_ctrlrequest *req)
163 151
164 usb_copy_from(req, &OTG_SETUPDAT, sizeof(struct usb_ctrlrequest)); 152 usb_copy_from(req, &OTG_SETUPDAT, sizeof(struct usb_ctrlrequest));
165 setup_data_valid = false; 153 setup_data_valid = false;
154
166 return 0; 155 return 0;
167} 156}
168 157
@@ -183,71 +172,82 @@ void usb_drv_set_address(int address)
183 /* UDC sets this automaticaly */ 172 /* UDC sets this automaticaly */
184} 173}
185 174
186/* TODO: Maybe adapt to irq scheme */ 175static void ep0_write(void)
176{
177 int xfer_size = MIN(ep0in.length, 64);
178
179 /* copy data to UDC buffer */
180 usb_copy_to(&OTG_EP0INDAT, ep0in.buf, xfer_size);
181 ep0in.buf += xfer_size;
182 ep0in.length -= xfer_size;
183
184 /* this marks data as ready to send */
185 OTG_IN0BC = xfer_size;
186}
187
187int usb_drv_send(int endpoint, void *ptr, int length) 188int usb_drv_send(int endpoint, void *ptr, int length)
188{ 189{
189 (void)endpoint; 190 (void)endpoint;
190 191
191 int xfer_size, cnt = length; 192 if (length)
192
193 while (cnt)
194 { 193 {
195 xfer_size = MIN(cnt, 64); 194 ep0in.length = length;
195 ep0in.buf = ptr;
196 ep0in.zlp = (length % 64 == 0) ? true : false;
197 ep0in.finished = false;
196 198
197 /* copy data to ep0in buffer */ 199 ep0_write();
198 usb_copy_to(&OTG_EP0INDAT, ptr, xfer_size);
199 200
200 /* this marks data as ready to send */ 201 while(!ep0in.finished)
201 OTG_IN0BC = xfer_size;
202
203 /* wait for the transfer end */
204 while(OTG_EP0CS & 0x04)
205 ; 202 ;
206
207 cnt -= xfer_size;
208 ptr += xfer_size;
209 } 203 }
210 204 else
211 /* ZLP stage */ 205 {
212 if((length % 64) == 0) 206 /* clear NAK bit to ACK host */
213 OTG_EP0CS = 2; 207 OTG_EP0CS = 2;
208 }
214 209
215 return 0; 210 return 0;
216} 211}
217 212
218/* TODO: Maybe adapt to irq scheme */ 213static int ep0_read(void)
219int usb_drv_recv(int endpoint, void* ptr, int length)
220{ 214{
221 (void)endpoint; 215 int xfer_size = OTG_OUT0BC;
222 int xfer_size, cnt = 0; 216 usb_copy_from(ep0out.buf, &OTG_EP0OUTDAT, xfer_size);
217 ep0out.buf += xfer_size;
218 ep0out.length -= xfer_size;
223 219
224 while (cnt < length) 220 return xfer_size;
225 { 221}
226 /* Arm receiving buffer by writing
227 * any value to OUT0BC. This sets
228 * OUT_BUSY bit in EP0CS until the data
229 * are correctly received and ACK'd
230 */
231 OTG_OUT0BC = 0;
232
233 while (OTG_EP0CS & 0x08)
234 ;
235
236 xfer_size = OTG_OUT0BC;
237
238 usb_copy_from(ptr, &OTG_EP0OUTDAT, xfer_size);
239 cnt += xfer_size;
240 ptr += xfer_size;
241
242 if (xfer_size < 64)
243 break;
244 }
245 222
246 /* ZLP stage */ 223int usb_drv_recv(int endpoint, void* ptr, int length)
247 if (length == 0) 224{
248 OTG_EP0CS = 2; 225 (void)endpoint;
249 226
250 return cnt; 227 ep0out.length = length;
228
229 if (length > 0)
230 {
231 ep0out.buf = ptr;
232 ep0out.finished = false;
233
234 /* Arm receiving buffer by writing
235 * any value to OUT0BC. This sets
236 * OUT_BUSY bit in EP0CS until the data
237 * are correctly received and ACK'd
238 */
239 OTG_OUT0BC = 0;
240
241 while (!ep0out.finished)
242 ;
243 }
244 else
245 {
246 /* clear NAK bit to ACK host */
247 OTG_EP0CS = 2;
248 }
249
250 return (length - ep0out.length);
251} 251}
252 252
253void usb_drv_stall(int endpoint, bool stall, bool in) 253void usb_drv_stall(int endpoint, bool stall, bool in)
@@ -265,3 +265,86 @@ void usb_drv_stall(int endpoint, bool stall, bool in)
265void usb_drv_exit(void) 265void usb_drv_exit(void)
266{ 266{
267} 267}
268
269void INT_UDC(void)
270{
271 /* get possible sources */
272 unsigned int usbirq = OTG_USBIRQ;
273 unsigned int otgirq = OTG_OTGIRQ;
274 unsigned int epinirq = OTG_IN04IRQ;
275 unsigned int epoutirq = OTG_OUT04IRQ;
276
277 /* HS, Reset, Setup */
278 if (usbirq)
279 {
280
281 if (usbirq & (1<<5)) /* HS irq */
282 {
283 udc_speed = USB_HIGH_SPEED;
284 }
285 else if (usbirq & (1<<4)) /* Reset irq */
286 {
287 cancel_all_transfers();
288 reset_all_fifos();
289
290 /* clear all pending EP irqs */
291 OTG_OUT04IRQ = 0xff;
292 OTG_IN04IRQ = 0xff;
293
294 udc_speed = USB_FULL_SPEED;
295 setup_data_valid = false;
296 }
297 else if (usbirq & (1<<0)) /* Setup data valid */
298 {
299 setup_data_valid = true;
300 }
301
302 /* clear irq flags */
303 OTG_USBIRQ = usbirq;
304 }
305
306 if (epoutirq)
307 {
308 if (ep0_read() == 64)
309 {
310 /* rearm receive buffer */
311 OTG_OUT0BC = 0;
312 }
313 else
314 {
315 /* short packet means end of transfer */
316 ep0out.finished = true;
317 }
318
319 /* ack interrupt */
320 OTG_OUT04IRQ = epoutirq;
321 }
322
323 if (epinirq)
324 {
325 if (ep0in.length)
326 {
327 ep0_write();
328 }
329 else
330 {
331 if (ep0in.zlp)
332 {
333 /* clear NAK bit to ACK hosts ZLP */
334 OTG_EP0CS = 2;
335 }
336
337 ep0in.finished = true;
338 }
339
340 /* ack interrupt */
341 OTG_IN04IRQ = epinirq;
342 }
343
344 if (otgirq)
345 {
346 OTG_OTGIRQ = otgirq;
347 }
348
349 OTG_USBEIRQ = 0x50;
350}