diff options
Diffstat (limited to 'utils/hwstub/stub/atj213x/usb_drv_atj213x.c')
-rw-r--r-- | utils/hwstub/stub/atj213x/usb_drv_atj213x.c | 307 |
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 @@ | |||
31 | volatile bool setup_data_valid = false; | 31 | volatile bool setup_data_valid = false; |
32 | volatile int udc_speed = USB_FULL_SPEED; | 32 | volatile int udc_speed = USB_FULL_SPEED; |
33 | 33 | ||
34 | struct endpoint_t | ||
35 | { | ||
36 | void *buf; | ||
37 | int length; | ||
38 | bool zlp; | ||
39 | bool finished; | ||
40 | }; | ||
41 | |||
42 | static volatile struct endpoint_t ep0in; | ||
43 | static volatile struct endpoint_t ep0out; | ||
44 | |||
34 | static void usb_copy_from(void *ptr, volatile void *reg, size_t sz) | 45 | static 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 | ||
70 | void INT_UDC(void) | 81 | static 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; | 94 | static 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 | ||
129 | void usb_drv_init(void) | 107 | void 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 | ||
159 | int usb_drv_recv_setup(struct usb_ctrlrequest *req) | 147 | int 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 */ | 175 | static 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 | |||
187 | int usb_drv_send(int endpoint, void *ptr, int length) | 188 | int 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 */ | 213 | static int ep0_read(void) |
219 | int 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 */ | 223 | int 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 | ||
253 | void usb_drv_stall(int endpoint, bool stall, bool in) | 253 | void usb_drv_stall(int endpoint, bool stall, bool in) |
@@ -265,3 +265,86 @@ void usb_drv_stall(int endpoint, bool stall, bool in) | |||
265 | void usb_drv_exit(void) | 265 | void usb_drv_exit(void) |
266 | { | 266 | { |
267 | } | 267 | } |
268 | |||
269 | void 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 | } | ||