1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /****************************************************************************
5 Contents : usb communication handling code for NanoXplore USB-JTAG *
6 ANGIE adapter hardware. *
7 Based on openULINK project code by: Martin Schmoelzer. *
8 Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
9 <aboudjelida@nanoxplore.com> *
10 <ahmederrachedbjld@gmail.com> *
11 *****************************************************************************/
17 #include "reg_ezusb.h"
18 #include <fx2macros.h>
22 /* Also update external declarations in "include/usb.h" if making changes to
25 volatile bool ep1_out
;
28 volatile __xdata __at
0xE6B8 struct setup_data setup_data
;
30 /* Define number of endpoints (except Control Endpoint 0) in a central place.
31 * Be sure to include the necessary endpoint descriptors!
33 #define NUM_ENDPOINTS 3
35 __code
struct usb_device_descriptor device_descriptor
= {
36 .blength
= sizeof(struct usb_device_descriptor
),
37 .bdescriptortype
= DESCRIPTOR_TYPE_DEVICE
,
38 .bcdusb
= 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */
39 .bdeviceclass
= 0xFF, /* 0xFF = vendor-specific */
40 .bdevicesubclass
= 0xFF,
41 .bdeviceprotocol
= 0xFF,
42 .bmaxpacketsize0
= 64,
49 .bnumconfigurations
= 1
52 /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
54 __code
struct usb_config_descriptor config_descriptor
= {
55 .blength
= sizeof(struct usb_config_descriptor
),
56 .bdescriptortype
= DESCRIPTOR_TYPE_CONFIGURATION
,
57 .wtotallength
= sizeof(struct usb_config_descriptor
) +
58 sizeof(struct usb_interface_descriptor
) +
59 (NUM_ENDPOINTS
* sizeof(struct usb_endpoint_descriptor
)),
61 .bconfigurationvalue
= 1,
62 .iconfiguration
= 4, /* String describing this configuration */
63 .bmattributes
= 0x80, /* Only MSB set according to USB spec */
64 .maxpower
= 50 /* 100 mA */
67 __code
struct usb_interface_descriptor interface_descriptor00
= {
68 .blength
= sizeof(struct usb_interface_descriptor
),
69 .bdescriptortype
= DESCRIPTOR_TYPE_INTERFACE
,
70 .binterfacenumber
= 0,
71 .balternatesetting
= 0,
72 .bnumendpoints
= NUM_ENDPOINTS
,
73 .binterfaceclass
= 0xFF,
74 .binterfacesubclass
= 0xFF,
75 .binterfaceprotocol
= 0xFF,
79 __code
struct usb_endpoint_descriptor bulk_ep1_out_endpoint_descriptor
= {
80 .blength
= sizeof(struct usb_endpoint_descriptor
),
81 .bdescriptortype
= 0x05,
82 .bendpointaddress
= (1 | USB_DIR_OUT
),
88 __code
struct usb_endpoint_descriptor bulk_ep1_in_endpoint_descriptor
= {
89 .blength
= sizeof(struct usb_endpoint_descriptor
),
90 .bdescriptortype
= 0x05,
91 .bendpointaddress
= (1 | USB_DIR_IN
),
97 __code
struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor
= {
98 .blength
= sizeof(struct usb_endpoint_descriptor
),
99 .bdescriptortype
= 0x05,
100 .bendpointaddress
= (2 | USB_DIR_OUT
),
101 .bmattributes
= 0x02,
102 .wmaxpacketsize
= 512,
106 __code
struct usb_endpoint_descriptor bulk_ep4_endpoint_descriptor
= {
107 .blength
= sizeof(struct usb_endpoint_descriptor
),
108 .bdescriptortype
= 0x05,
109 .bendpointaddress
= (4 | USB_DIR_IN
),
110 .bmattributes
= 0x02,
111 .wmaxpacketsize
= 512,
115 __code
struct usb_endpoint_descriptor bulk_ep6_endpoint_descriptor
= {
116 .blength
= sizeof(struct usb_endpoint_descriptor
),
117 .bdescriptortype
= 0x05,
118 .bendpointaddress
= (6 | USB_DIR_OUT
),
119 .bmattributes
= 0x02,
120 .wmaxpacketsize
= 512,
124 __code
struct usb_endpoint_descriptor bulk_ep8_endpoint_descriptor
= {
125 .blength
= sizeof(struct usb_endpoint_descriptor
),
126 .bdescriptortype
= 0x05,
127 .bendpointaddress
= (8 | USB_DIR_OUT
),
128 .bmattributes
= 0x02,
129 .wmaxpacketsize
= 512,
133 __code
struct usb_language_descriptor language_descriptor
= {
135 .bdescriptortype
= DESCRIPTOR_TYPE_STRING
,
136 .wlangid
= {0x0409 /* US English */}
139 __code
struct usb_string_descriptor strmanufacturer
=
140 STR_DESCR(16, 'N', 'a', 'n', 'o', 'X', 'p', 'l', 'o', 'r', 'e', ',', ' ', 'S', 'A', 'S', '.');
142 __code
struct usb_string_descriptor strproduct
=
143 STR_DESCR(13, 'A', 'N', 'G', 'I', 'E', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
145 __code
struct usb_string_descriptor strserialnumber
=
146 STR_DESCR(6, '0', '0', '0', '0', '0', '1');
148 __code
struct usb_string_descriptor strconfigdescr
=
149 STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
151 /* Table containing pointers to string descriptors */
152 __code
struct usb_string_descriptor
*__code en_string_descriptors
[4] = {
158 void sudav_isr(void)__interrupt SUDAV_ISR
160 EXIF
&= ~0x10; /* Clear USBINT: Main global interrupt */
163 usb_handle_setup_data();
165 void sof_isr(void)__interrupt SOF_ISR
168 void sutok_isr(void)__interrupt SUTOK_ISR
171 void suspend_isr(void)__interrupt SUSPEND_ISR
174 void usbreset_isr(void)__interrupt USBRESET_ISR
177 void highspeed_isr(void)__interrupt HIGHSPEED_ISR
180 void ep0ack_isr(void)__interrupt EP0ACK_ISR
183 void stub_isr(void)__interrupt STUB_ISR
186 void ep0in_isr(void)__interrupt EP0IN_ISR
189 void ep0out_isr(void)__interrupt EP0OUT_ISR
192 void ep1in_isr(void)__interrupt EP1IN_ISR
196 EXIF
&= ~0x10; /* Clear USBINT: Main global interrupt */
197 EPIRQ
= 0x04; /* Clear individual EP1IN IRQ */
199 void ep1out_isr(void)__interrupt EP1OUT_ISR
203 EXIF
&= ~0x10; /* Clear USBINT: Main global interrupt */
204 EPIRQ
= 0x08; /* Clear individual EP1OUT IRQ */
206 void ep2_isr(void)__interrupt EP2_ISR
208 ep1_out
= false; /* Does nothing but required by the compiler */
210 void ep4_isr(void)__interrupt EP4_ISR
213 void ep6_isr(void)__interrupt EP6_ISR
216 void ep8_isr(void)__interrupt EP8_ISR
219 void ibn_isr(void)__interrupt IBN_ISR
222 void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR
225 void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR
228 void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR
231 void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR
234 void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR
237 void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR
240 void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR
243 void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR
246 void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR
249 void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR
252 void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR
255 void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR
258 void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR
261 void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR
264 void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR
267 void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR
270 void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR
273 void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR
276 void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR
279 void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR
282 void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR
285 void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR
288 void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR
291 void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR
294 void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR
299 * Return the control/status register for an endpoint
301 * @param ep endpoint address
302 * @return on success: pointer to Control & Status register for endpoint
304 * @return on failure: NULL
306 __xdata
uint8_t *usb_get_endpoint_cs_reg(uint8_t ep
)
308 /* Mask direction bit */
309 uint8_t ep_num
= ep
& ~0x80;
315 return ep
& 0x80 ? &EP1INCS
: &EP1OUTCS
;
329 void usb_reset_data_toggle(uint8_t ep
)
332 +----+-----+-----+------+-----+-------+-------+-------+
333 | Q | S | R | IO | EP3 | EP2 | EP1 | EP0 |
334 +----+-----+-----+------+-----+-------+-------+-------+
336 To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
337 to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
338 separate write cycle, the R bit needs to be set.
340 TOGCTL
= (((ep
& 0x80) >> 3) + (ep
& 0x0F));
341 TOGCTL
|= BMRESETTOGGLE
;
345 * Handle GET_STATUS request.
347 * @return on success: true
348 * @return on failure: false
350 bool usb_handle_get_status(void)
353 switch (setup_data
.bmrequesttype
) {
355 /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
356 * Byte 1: reserved, reset to zero */
367 /* Always return two zero bytes according to USB 1.1 spec, p. 191 */
378 /* Get stall bit for endpoint specified in low byte of wIndex */
379 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.windex
& 0xff);
381 if (*ep_cs
& EPSTALL
)
386 /* Second byte sent has to be always zero */
402 * Handle CLEAR_FEATURE request.
404 * @return on success: true
405 * @return on failure: false
407 bool usb_handle_clear_feature(void)
409 __xdata
uint8_t *ep_cs
;
411 switch (setup_data
.bmrequesttype
) {
413 /* Clear remote wakeup not supported: stall EP0 */
417 if (setup_data
.wvalue
== 0) {
418 /* Unstall the endpoint specified in wIndex */
419 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.windex
);
424 /* Unsupported feature, stall EP0 */
429 /* Vendor commands... */
436 * Handle SET_FEATURE request.
438 * @return on success: true
439 * @return on failure: false
441 bool usb_handle_set_feature(void)
443 __xdata
uint8_t *ep_cs
;
445 switch (setup_data
.bmrequesttype
) {
447 if (setup_data
.wvalue
== 2)
451 if (setup_data
.wvalue
== 0) {
452 /* Stall the endpoint specified in wIndex */
453 ep_cs
= usb_get_endpoint_cs_reg(setup_data
.windex
);
458 /* Unsupported endpoint feature */
463 /* Vendor commands... */
471 * Handle GET_DESCRIPTOR request.
473 * @return on success: true
474 * @return on failure: false
476 bool usb_handle_get_descriptor(void)
478 __xdata
uint8_t descriptor_type
;
479 __xdata
uint8_t descriptor_index
;
481 descriptor_type
= (setup_data
.wvalue
& 0xff00) >> 8;
482 descriptor_index
= setup_data
.wvalue
& 0x00ff;
484 switch (descriptor_type
) {
485 case DESCRIPTOR_TYPE_DEVICE
:
486 SUDPTRH
= HI8(&device_descriptor
);
487 SUDPTRL
= LO8(&device_descriptor
);
489 case DESCRIPTOR_TYPE_CONFIGURATION
:
490 SUDPTRH
= HI8(&config_descriptor
);
491 SUDPTRL
= LO8(&config_descriptor
);
493 case DESCRIPTOR_TYPE_STRING
:
494 if (setup_data
.windex
== 0) {
495 /* Supply language descriptor */
496 SUDPTRH
= HI8(&language_descriptor
);
497 SUDPTRL
= LO8(&language_descriptor
);
498 } else if (setup_data
.windex
== 0x0409 /* US English */) {
499 /* Supply string descriptor */
500 SUDPTRH
= HI8(en_string_descriptors
[descriptor_index
- 1]);
501 SUDPTRL
= LO8(en_string_descriptors
[descriptor_index
- 1]);
507 /* Unsupported descriptor type */
514 * Handle SET_INTERFACE request.
516 void usb_handle_set_interface(void)
518 /* Reset Data Toggle */
519 usb_reset_data_toggle(USB_DIR_IN
| 4);
520 usb_reset_data_toggle(USB_DIR_OUT
| 2);
522 /* Unstall & clear busy flag of all valid IN endpoints */
525 /* Unstall all valid OUT endpoints, reset bytecounts */
531 /* Initialize GPIF interface transfer count */
532 void set_gpif_cnt(uint32_t count
)
534 GPIFTCB3
= (uint8_t)(((uint32_t)(count
) >> 24) & 0x000000ff);
536 GPIFTCB2
= (uint8_t)(((uint32_t)(count
) >> 16) & 0x000000ff);
538 GPIFTCB1
= (uint8_t)(((uint32_t)(count
) >> 8) & 0x000000ff);
540 GPIFTCB0
= (uint8_t)((uint32_t)(count
) & 0x000000ff);
544 * Vendor commands handling:
546 #define VR_CFGOPEN 0xB0
547 #define VR_CFGCLOSE 0xB1
551 uint8_t __xdata
*eptr
;
553 uint32_t __xdata gcnt
;
554 bool usb_handle_send_bitstream(void)
556 eptr
= EP0BUF
; /* points to EP0BUF 64-byte register */
557 wcnt
= setup_data
.wlength
; /* total transfer count */
559 /* Clear EP0BUF for OUT requests */
560 if (setup_data
.bmrequesttype
& 0x80) {
561 bcnt
= ((wcnt
> 64) ? 64 : wcnt
);
562 for (ix
= 0; ix
< bcnt
; ix
++)
566 switch (setup_data
.brequest
) {
568 /* Clear bytecount / to allow new data in / to stops NAKing */
571 while (EP0CS
& EPBSY
)
572 ; /* wait to finish transferring in EP0BUF, until not busy */
573 gcnt
= ((uint32_t)(eptr
[0]) << 24) | ((uint32_t)(eptr
[1]) << 16)
574 | ((uint32_t)(eptr
[2]) << 8) | (uint32_t)(eptr
[3]);
575 /* Angie board FPGA bitstream download */
576 switch ((setup_data
.wvalue
) & 0x00C0) {
578 PIN_PROGRAM_B
= 0; /* Apply RPGM- pulse */
579 GPIFWFSELECT
= 0xF2; /* Restore Config mode waveforms select */
581 EP2FIFOCFG
= BMAUTOOUT
; /* and Automatic 8-bit GPIF OUT mode */
583 PIN_PROGRAM_B
= 1; /* Negate RPGM- pulse */
584 delay_ms(10); /* FPGA init time < 10mS */
585 set_gpif_cnt(gcnt
); /* Initialize GPIF interface transfer count */
588 GPIFTRIG
= GPIF_EP2
; /* Trigger GPIF OUT transfer on EP2 */
597 /* wait until GPIF transaction has been completed */
598 while ((GPIFTRIG
& BMGPIFDONE
) == 0) {
600 printf("GPIF done time out\n");
605 switch ((setup_data
.wvalue
) & 0x00C0) {
609 IFCONFIG
&= 0xFC; /* Exit gpif mode */
615 EP0BCL
= (uint8_t)(setup_data
.wlength
); /* Signal buffer is filled */
618 return true; /* Error: unknown VR command */
620 return false; /* no error; command handled OK */
624 * Handle the arrival of a USB Control Setup Packet.
626 void usb_handle_setup_data(void)
628 switch (setup_data
.brequest
) {
630 if (!usb_handle_get_status())
634 if (!usb_handle_clear_feature())
638 /* Reserved values */
642 if (!usb_handle_set_feature())
646 /* Handled by USB core */
649 /* Set Descriptor not supported. */
653 if (!usb_handle_get_descriptor())
656 case GET_CONFIGURATION
:
657 /* ANGIE has only one configuration, return its index */
658 EP0BUF
[0] = config_descriptor
.bconfigurationvalue
;
663 case SET_CONFIGURATION
:
664 /* ANGIE has only one configuration -> nothing to do */
667 /* ANGIE only has one interface, return its number */
668 EP0BUF
[0] = interface_descriptor00
.binterfacenumber
;
674 usb_handle_set_interface();
677 /* Isochronous endpoints not used -> nothing to do */
680 /* if not Vendor command, Stall EndPoint 0 */
681 if (usb_handle_send_bitstream())
688 * Handle the initialization of endpoints.
717 /* Standard procedure to reset FIFOs */
718 FIFORESET
= BMNAKALL
; /* NAK all transfers during the reset */
720 FIFORESET
= 0x02; /* reset EP2 FIFO */
722 FIFORESET
= 0x00; /* deactivate the NAK all */
726 EP2FIFOCFG
= BMAUTOOUT
; /* Automatic 8-bit GPIF OUT mode */
731 * Interrupt initialization. Configures USB interrupts.
733 void interrupt_init(void)
735 /* Enable Interrupts */
738 /* Enable USB interrupt (EIE register) */
742 /* Enable INT 2 & 4 Autovectoring */
743 INTSETUP
|= (AV2EN
| AV4EN
);
745 /* Enable individual EP1OUT&IN interrupts */
748 /* Clear individual USB interrupt IRQ */
751 /* Enable SUDAV interrupt */
754 /* Clear SUDAV interrupt */
759 * Handle the initialization of io ports.
764 PORTACFG
= 0x01; /* 0: normal ou 1: alternate function (each bit) */
765 OEA
= 0xEF; /* all OUT exept INIT_B IN */
772 OEB
= 0xEF; /* all OUT exept TDO */
781 PORTCCFG
= 0x00; /* 0: normal ou 1: alternate function (each bit) */
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)