summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2016-11-10 12:54:12 +0100
committerMarcin Bukat <marcin.bukat@gmail.com>2016-11-10 13:57:02 +0100
commitba9f405dc47c1ec24327537b77a61c886ad13f34 (patch)
tree680e5b9cc997a2d74d7f6a9ff8dc1171a2324a4e
parentf2da975be636961df6375abe92d05a6b52da34b2 (diff)
downloadrockbox-ba9f405dc47c1ec24327537b77a61c886ad13f34.tar.gz
rockbox-ba9f405dc47c1ec24327537b77a61c886ad13f34.zip
ATJ hwstub make irq based usb driver work
0e2b490 introduced rework of usb driver which was broken. It was reverted in f2da975 to restore hwstub functionality on ATJ. This commit reenables usb rework AND fixes remining issues. The problem was with 0 length OUT thransfers. Additionally a few cleanups were made. Change-Id: I529ea9ad6540509e9287ca7e1cd2b44369b03cbb
-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}