diff options
Diffstat (limited to 'firmware/target/arm/as3525/usb-drv-as3525v2.c')
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.c | 134 |
1 files changed, 105 insertions, 29 deletions
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.c b/firmware/target/arm/as3525/usb-drv-as3525v2.c index 369a838c65..98805ca578 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.c +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.c | |||
@@ -48,9 +48,6 @@ struct usb_endpoint | |||
48 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2]; | 48 | static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2]; |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | static unsigned int usb_num_in_ep = 0; | ||
52 | static unsigned int usb_num_out_ep = 0; | ||
53 | |||
54 | void usb_attach(void) | 51 | void usb_attach(void) |
55 | { | 52 | { |
56 | usb_enable(true); | 53 | usb_enable(true); |
@@ -100,6 +97,8 @@ static void as3525v2_connect(void) | |||
100 | /* 11) Do something that is probably CCU related but undocumented*/ | 97 | /* 11) Do something that is probably CCU related but undocumented*/ |
101 | CCU_USB_THINGY &= ~0x1000; | 98 | CCU_USB_THINGY &= ~0x1000; |
102 | usb_delay(); | 99 | usb_delay(); |
100 | CCU_USB_THINGY &= ~0x300000; | ||
101 | usb_delay(); | ||
103 | /* 12) reset usb core parameters (dev addr, speed, ...) */ | 102 | /* 12) reset usb core parameters (dev addr, speed, ...) */ |
104 | USB_DCFG = 0; | 103 | USB_DCFG = 0; |
105 | usb_delay(); | 104 | usb_delay(); |
@@ -122,6 +121,31 @@ static void usb_enable_common_interrupts(void) | |||
122 | USB_GINTMSK_sessreqintr; | 121 | USB_GINTMSK_sessreqintr; |
123 | } | 122 | } |
124 | 123 | ||
124 | static void usb_enable_device_interrupts(void) | ||
125 | { | ||
126 | /* Disable all interrupts */ | ||
127 | USB_GINTMSK = 0; | ||
128 | /* Clear any pending interrupt */ | ||
129 | USB_GINTSTS = 0xffffffff; | ||
130 | /* Enable common interrupts */ | ||
131 | usb_enable_common_interrupts(); | ||
132 | /* Enable interrupts */ | ||
133 | USB_GINTMSK |= | ||
134 | USB_GINTMSK_usb_rst | ||
135 | | USB_GINTMSK_enumdone | ||
136 | | USB_GINTMSK_inepintr | ||
137 | | USB_GINTMSK_outepintr | ||
138 | | USB_GINTMSK_erlysuspend | ||
139 | | USB_GINTMSK_epmismatch /* only if multiple tx fifos enabled */ | ||
140 | #if 0 /* only if periodic fifo used */ | ||
141 | | USB_GINTMSK_isooutdrop | ||
142 | | USB_GINTMSK_eopframe | ||
143 | | USB_GINTMSK_incomplisoin | ||
144 | | USB_GINTMSK_incomplisoout | ||
145 | #endif | ||
146 | ; | ||
147 | } | ||
148 | |||
125 | static void usb_flush_tx_fifos(int nums) | 149 | static void usb_flush_tx_fifos(int nums) |
126 | { | 150 | { |
127 | unsigned int i = 0; | 151 | unsigned int i = 0; |
@@ -171,16 +195,33 @@ static void core_reset(void) | |||
171 | /* Wait for 3 PHY Clocks */ | 195 | /* Wait for 3 PHY Clocks */ |
172 | /*mdelay(100);*/ | 196 | /*mdelay(100);*/ |
173 | sleep(1); | 197 | sleep(1); |
198 | } | ||
174 | 199 | ||
175 | /* Check hardware capabilityies */ | 200 | static void core_dev_init(void) |
201 | { | ||
202 | unsigned int usb_num_in_ep = 0; | ||
203 | unsigned int usb_num_out_ep = 0; | ||
204 | unsigned int i; | ||
205 | /* Restart the phy clock */ | ||
206 | USB_PCGCCTL = 0; | ||
207 | /* Set phy speed : high speed */ | ||
208 | USB_DCFG = (USB_DCFG & (~USB_DCFG_devspd_bits)) | USB_DCFG_devspd_hs_phy_hs; | ||
209 | /* Set periodic frame interval */ | ||
210 | USB_DCFG = (USB_DCFG & (~USB_DCFG_perfrint_bits)) | (USB_DCFG_FRAME_INTERVAL_80 << USB_DCFG_perfrint_bit_pos); | ||
211 | |||
212 | /* Check hardware capabilities */ | ||
176 | if(USB_GHWCFG2_ARCH != USB_INT_DMA_ARCH) | 213 | if(USB_GHWCFG2_ARCH != USB_INT_DMA_ARCH) |
177 | panicf("usb: wrong architecture (%ld)", USB_GHWCFG2_ARCH); | 214 | panicf("usb: wrong architecture (%ld)", USB_GHWCFG2_ARCH); |
178 | if(USB_GHWCFG2_HS_PHY_TYPE != USB_PHY_TYPE_UTMI) | 215 | if(USB_GHWCFG2_HS_PHY_TYPE != USB_PHY_TYPE_UTMI) |
179 | panicf("usb: wrong HS phy type (%ld)", USB_GHWCFG2_HS_PHY_TYPE); | 216 | panicf("usb: wrong HS phy type (%ld)", USB_GHWCFG2_HS_PHY_TYPE); |
180 | if(USB_GHWCFG2_FS_PHY_TYPE != USB_PHY_TYPE_UNSUPPORTED) | 217 | if(USB_GHWCFG2_FS_PHY_TYPE != USB_PHY_TYPE_UNSUPPORTED) |
181 | panicf("usb: wrong FS phy type (%ld)", USB_GHWCFG2_FS_PHY_TYPE); | 218 | panicf("usb: wrong FS phy type (%ld)", USB_GHWCFG2_FS_PHY_TYPE); |
219 | #ifdef USB_USE_CUSTOM_FIFO_LAYOUT | ||
182 | if(USB_GHWCFG2_DYN_FIFO != 1) | 220 | if(USB_GHWCFG2_DYN_FIFO != 1) |
183 | panicf("usb: no dynamic fifo"); | 221 | panicf("usb: no dynamic fifo"); |
222 | if(USB_GRXFSIZ != USB_DATA_FIFO_DEPTH) | ||
223 | panicf("usb: wrong data fifo size"); | ||
224 | #endif /* USB_USE_CUSTOM_FIFO_LAYOUT */ | ||
184 | if(USB_GHWCFG4_UTMI_PHY_DATA_WIDTH != 0x2) | 225 | if(USB_GHWCFG4_UTMI_PHY_DATA_WIDTH != 0x2) |
185 | panicf("usb: wrong utmi data width (%ld)", USB_GHWCFG4_UTMI_PHY_DATA_WIDTH); | 226 | panicf("usb: wrong utmi data width (%ld)", USB_GHWCFG4_UTMI_PHY_DATA_WIDTH); |
186 | if(USB_GHWCFG4_DED_FIFO_EN != 1) /* it seems to be multiple tx fifo support */ | 227 | if(USB_GHWCFG4_DED_FIFO_EN != 1) /* it seems to be multiple tx fifo support */ |
@@ -205,19 +246,27 @@ static void core_reset(void) | |||
205 | 246 | ||
206 | if(usb_num_in_ep != USB_GHWCFG4_NUM_IN_EP) | 247 | if(usb_num_in_ep != USB_GHWCFG4_NUM_IN_EP) |
207 | panicf("usb: num in ep mismatch(%d,%lu)", usb_num_in_ep, USB_GHWCFG4_NUM_IN_EP); | 248 | panicf("usb: num in ep mismatch(%d,%lu)", usb_num_in_ep, USB_GHWCFG4_NUM_IN_EP); |
249 | if(usb_num_in_ep != USB_NUM_IN_EP) | ||
250 | panicf("usb: num in ep static mismatch(%u,%u)", usb_num_in_ep, USB_NUM_IN_EP); | ||
251 | if(usb_num_out_ep != USB_NUM_OUT_EP) | ||
252 | panicf("usb: num out ep static mismatch(%u,%u)", usb_num_out_ep, USB_NUM_OUT_EP); | ||
208 | 253 | ||
209 | logf("%d in ep, %d out ep", usb_num_in_ep, usb_num_out_ep); | 254 | logf("%d in ep, %d out ep", usb_num_in_ep, usb_num_out_ep); |
210 | logf("initial:"); | 255 | logf("initial:"); |
211 | logf(" tot fifo sz: %ld", USB_GHWCFG3_DFIFO_LEN); | 256 | logf(" tot fifo sz: %lx", USB_GHWCFG3_DFIFO_LEN); |
212 | logf(" rx fifo sz: %ld", USB_GRXFSIZ); | 257 | logf(" rx fifo: [%04x,+%4lx]", 0, USB_GRXFSIZ); |
213 | logf(" tx fifo sz: %ld", USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ)); /* there is no perio ep so print only non-perio */ | 258 | logf(" nptx fifo: [%04lx,+%4lx]", USB_GET_FIFOSIZE_START_ADR(USB_GNPTXFSIZ), |
214 | for(i = 1; i <= USB_GHWCFG4_NUM_IN_EP; i++) | 259 | USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ)); |
260 | for(i = 1; i <= USB_NUM_IN_EP; i++) | ||
215 | { | 261 | { |
216 | logf(" dieptx fifo sd (%2u): %ld", i, USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i))); | 262 | logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i, |
263 | USB_GET_FIFOSIZE_START_ADR(USB_DIEPTXFSIZ(i)), | ||
264 | USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i))); | ||
217 | } | 265 | } |
218 | 266 | ||
267 | #ifdef USB_USE_CUSTOM_FIFO_LAYOUT | ||
219 | /* Setup FIFOs */ | 268 | /* Setup FIFOs */ |
220 | /* Organize FIFO as follow (unsure): | 269 | /* Organize FIFO as follow: |
221 | * 0 -> rxfsize : RX fifo | 270 | * 0 -> rxfsize : RX fifo |
222 | * rxfsize -> rxfsize + nptxfsize : TX fifo for first IN ep | 271 | * rxfsize -> rxfsize + nptxfsize : TX fifo for first IN ep |
223 | * rxfsize + nptxfsize -> rxfsize + 2 * nptxfsize : TX fifo for second IN ep | 272 | * rxfsize + nptxfsize -> rxfsize + 2 * nptxfsize : TX fifo for second IN ep |
@@ -225,14 +274,17 @@ static void core_reset(void) | |||
225 | * ... | 274 | * ... |
226 | */ | 275 | */ |
227 | 276 | ||
228 | unsigned short adr = USB_GRXFSIZ; | 277 | unsigned short adr = 0; |
229 | unsigned short depth = USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ); | 278 | unsigned short depth = USB_RX_FIFO_SIZE; |
279 | USB_GRXFSIZ = depth; | ||
280 | adr += depth; | ||
281 | depth = USB_NPTX_FIFO_SIZE; | ||
230 | USB_GNPTXFSIZ = USB_MAKE_FIFOSIZE_DATA(adr, depth); | 282 | USB_GNPTXFSIZ = USB_MAKE_FIFOSIZE_DATA(adr, depth); |
231 | adr += depth; | 283 | adr += depth; |
232 | 284 | ||
233 | for(i = 1; i <= USB_GHWCFG4_NUM_IN_EP; i++) | 285 | for(i = 1; i <= USB_NUM_IN_EP; i++) |
234 | { | 286 | { |
235 | depth = USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i)); | 287 | depth = USB_EPTX_FIFO_SIZE; |
236 | USB_DIEPTXFSIZ(i) = USB_MAKE_FIFOSIZE_DATA(adr, depth); | 288 | USB_DIEPTXFSIZ(i) = USB_MAKE_FIFOSIZE_DATA(adr, depth); |
237 | adr += depth; | 289 | adr += depth; |
238 | } | 290 | } |
@@ -241,13 +293,17 @@ static void core_reset(void) | |||
241 | logf(" rx fifo: [%04x,+%4lx]", 0, USB_GRXFSIZ); | 293 | logf(" rx fifo: [%04x,+%4lx]", 0, USB_GRXFSIZ); |
242 | logf(" nptx fifo: [%04lx,+%4lx]", USB_GET_FIFOSIZE_START_ADR(USB_GNPTXFSIZ), | 294 | logf(" nptx fifo: [%04lx,+%4lx]", USB_GET_FIFOSIZE_START_ADR(USB_GNPTXFSIZ), |
243 | USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ)); | 295 | USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ)); |
244 | for(i = 1; i <= USB_GHWCFG4_NUM_IN_EP; i++) | 296 | for(i = 1; i <= USB_NUM_IN_EP; i++) |
245 | { | 297 | { |
246 | logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i, | 298 | logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i, |
247 | USB_GET_FIFOSIZE_START_ADR(USB_DIEPTXFSIZ(i)), | 299 | USB_GET_FIFOSIZE_START_ADR(USB_DIEPTXFSIZ(i)), |
248 | USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i))); | 300 | USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i))); |
249 | } | 301 | } |
250 | 302 | ||
303 | if(adr > USB_DATA_FIFO_DEPTH) | ||
304 | panicf("usb: total data fifo size exceeded"); | ||
305 | #endif /* USB_USE_CUSTOM_FIFO_LAYOUT */ | ||
306 | |||
251 | /* flush the fifos */ | 307 | /* flush the fifos */ |
252 | usb_flush_tx_fifos(0x10); /* flush all */ | 308 | usb_flush_tx_fifos(0x10); /* flush all */ |
253 | usb_flush_rx_fifo(); | 309 | usb_flush_rx_fifo(); |
@@ -261,7 +317,7 @@ static void core_reset(void) | |||
261 | USB_DAINT = 0xffffffff; | 317 | USB_DAINT = 0xffffffff; |
262 | USB_DAINTMSK = 0; | 318 | USB_DAINTMSK = 0; |
263 | 319 | ||
264 | for(i = 0; i <= usb_num_in_ep; i++) | 320 | for(i = 0; i <= USB_NUM_IN_EP; i++) |
265 | { | 321 | { |
266 | /* disable endpoint if enabled */ | 322 | /* disable endpoint if enabled */ |
267 | if(USB_DIEPCTL(i) & USB_DEPCTL_epena) | 323 | if(USB_DIEPCTL(i) & USB_DEPCTL_epena) |
@@ -274,7 +330,7 @@ static void core_reset(void) | |||
274 | USB_DIEPINT(i) = 0xff; | 330 | USB_DIEPINT(i) = 0xff; |
275 | } | 331 | } |
276 | 332 | ||
277 | for(i = 0; i <= usb_num_out_ep; i++) | 333 | for(i = 0; i <= USB_NUM_OUT_EP; i++) |
278 | { | 334 | { |
279 | /* disable endpoint if enabled */ | 335 | /* disable endpoint if enabled */ |
280 | if(USB_DOEPCTL(i) & USB_DEPCTL_epena) | 336 | if(USB_DOEPCTL(i) & USB_DEPCTL_epena) |
@@ -286,17 +342,21 @@ static void core_reset(void) | |||
286 | USB_DOEPDMA(i) = 0; | 342 | USB_DOEPDMA(i) = 0; |
287 | USB_DOEPINT(i) = 0xff; | 343 | USB_DOEPINT(i) = 0xff; |
288 | } | 344 | } |
289 | } | ||
290 | 345 | ||
291 | static void core_dev_init(void) | 346 | /* fixme: threshold tweaking only takes place if we use multiple tx fifos it seems */ |
292 | { | 347 | /* only dump them for now, leave threshold disabled */ |
293 | /* Restart the phy clock */ | 348 | logf("threshold control:"); |
294 | USB_PCGCCTL = 0; | 349 | logf(" non_iso_thr_en: %d", (USB_DTHRCTL & USB_DTHRCTL_non_iso_thr_en) ? 1 : 0); |
295 | /* Set phy speed : high speed */ | 350 | logf(" iso_thr_en: %d", (USB_DTHRCTL & USB_DTHRCTL_iso_thr_en) ? 1 : 0); |
296 | USB_DCFG = (USB_DCFG & (~USB_DCFG_devspd_bits)) | USB_DCFG_devspd_hs_phy_hs; | 351 | logf(" tx_thr_len: %lu", (USB_DTHRCTL & USB_DTHRCTL_tx_thr_len_bits) >> USB_DTHRCTL_tx_thr_len_bit_pos); |
297 | /* Set periodic frame interval */ | 352 | logf(" rx_thr_en: %d", (USB_DTHRCTL & USB_DTHRCTL_rx_thr_en) ? 1 : 0); |
298 | USB_DCFG = (USB_DCFG & (~USB_DCFG_perfrint_bits)) | (USB_DCFG_FRAME_INTERVAL_80 << USB_DCFG_perfrint_bit_pos); | 353 | logf(" rx_thr_len: %lu", (USB_DTHRCTL & USB_DTHRCTL_rx_thr_len_bits) >> USB_DTHRCTL_rx_thr_len_bit_pos); |
299 | /* Configure data fifo size */ | 354 | |
355 | /* enable USB interrupts */ | ||
356 | usb_enable_device_interrupts(); | ||
357 | |||
358 | /* enable fifo underrun interrupt ? */ | ||
359 | USB_DIEPMSK |= USB_DIEPINT_txfifoundrn; | ||
300 | } | 360 | } |
301 | 361 | ||
302 | static void core_init(void) | 362 | static void core_init(void) |
@@ -336,14 +396,30 @@ static void core_init(void) | |||
336 | core_dev_init(); | 396 | core_dev_init(); |
337 | } | 397 | } |
338 | 398 | ||
399 | static void usb_enable_global_interrupts(void) | ||
400 | { | ||
401 | VIC_INT_ENABLE = INTERRUPT_USB; | ||
402 | USB_GAHBCFG |= USB_GAHBCFG_glblintrmsk; | ||
403 | } | ||
404 | |||
405 | static void usb_disable_global_interrupts(void) | ||
406 | { | ||
407 | USB_GAHBCFG &= ~USB_GAHBCFG_glblintrmsk; | ||
408 | VIC_INT_EN_CLEAR = INTERRUPT_USB; | ||
409 | } | ||
410 | |||
339 | void usb_drv_init(void) | 411 | void usb_drv_init(void) |
340 | { | 412 | { |
341 | logf("usb_drv_init"); | 413 | logf("usb_drv_init"); |
414 | /* Enable PHY and clocks (but leave pullups disabled) */ | ||
342 | as3525v2_connect(); | 415 | as3525v2_connect(); |
343 | 416 | /* Disable global interrupts */ | |
417 | usb_disable_global_interrupts(); | ||
344 | logf("usb: synopsis id: %lx", USB_GSNPSID); | 418 | logf("usb: synopsis id: %lx", USB_GSNPSID); |
345 | 419 | /* Core init */ | |
346 | core_init(); | 420 | core_init(); |
421 | /* Enable global interrupts */ | ||
422 | usb_enable_global_interrupts(); | ||
347 | } | 423 | } |
348 | 424 | ||
349 | void usb_drv_exit(void) | 425 | void usb_drv_exit(void) |