forked from lowRISC/opentitan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dif_usbdev.h
960 lines (899 loc) · 33.6 KB
/
dif_usbdev.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_USBDEV_H_
#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_USBDEV_H_
/**
* @file
* @brief <a href="/hw/ip/usbdev/doc/">USB Device</a> Device Interface Functions
*/
#include <stddef.h>
#include <stdint.h>
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"
#include "sw/device/lib/dif/autogen/dif_usbdev_autogen.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Hardware constants.
*/
#define USBDEV_NUM_ENDPOINTS 12
#define USBDEV_MAX_PACKET_SIZE 64
// Internal constant that should not be used by clients. Defined here because
// it is used in the definition of `dif_usbdev_buffer_pool` below.
#define USBDEV_NUM_BUFFERS 32
// Constants used for the `dif_usbdev_endpoint_id` direction field.
#define USBDEV_ENDPOINT_DIR_IN 1
#define USBDEV_ENDPOINT_DIR_OUT 0
typedef struct dif_usbdev_endpoint_id {
/**
* Endpoint number.
*/
unsigned int number : 4;
/**
* Reserved. Should be zero.
*/
unsigned int reserved : 3;
/**
* Endpoint direction. 1 = IN endpoint, 0 = OUT endpoint
*/
unsigned int direction : 1;
} dif_usbdev_endpoint_id_t;
/**
* Free buffer pool.
*
* A USB device has a fixed number of buffers that are used for storing incoming
* and outgoing packets and the software is responsible for keeping track of
* free buffers. The pool is implemented as a stack for constant-time add and
* remove. `top` points to the last free buffer added to the pool. The pool is
* full when `top == USBDEV_NUM_BUFFERS - 1` and empty when `top == -1`.
*/
typedef struct dif_usbdev_buffer_pool {
uint8_t buffers[USBDEV_NUM_BUFFERS];
int8_t top;
} dif_usbdev_buffer_pool_t;
/**
* Buffer types.
*/
typedef enum dif_usbdev_buffer_type {
/**
* For reading payloads of incoming packets.
*/
kDifUsbdevBufferTypeRead,
/**
* For writing payloads of outgoing packets.
*/
kDifUsbdevBufferTypeWrite,
/**
* Clients must not use a buffer after it is handed over to hardware or
* returned to the free buffer pool. This type exists to protect against such
* cases.
*/
kDifUsbdevBufferTypeStale,
} dif_usbdev_buffer_type_t;
/**
* A USB device buffer.
*
* This struct represents a USB device buffer that has been provided to a client
* in response to a buffer request. Clients should treat instances of this
* struct as opaque objects and should pass them to the appropriate functions of
* this library to read and write payloads of incoming and outgoing packets,
* respectively.
*
* See also: `dif_usbdev_recv`, `dif_usbdev_buffer_read`,
* `dif_usbdev_buffer_request`, `dif_usbdev_buffer_write`,
* `dif_usbdev_send`, `dif_usbdev_buffer_return`.
*/
typedef struct dif_usbdev_buffer {
/**
* Hardware buffer id.
*/
uint8_t id;
/**
* Byte offset for the next read or write operation.
*/
uint8_t offset;
/**
* For read buffers: remaining number of bytes to read.
* For write buffers: remaining number of bytes that can be written.
*/
uint8_t remaining_bytes;
/**
* Type of this buffer.
*/
dif_usbdev_buffer_type_t type;
} dif_usbdev_buffer_t;
/**
* Configuration for initializing a USB device.
*/
typedef struct dif_usbdev_config {
/**
* Activate the single-ended D signal for detecting K and J symbols, for use
* with a differential receiver.
*/
dif_toggle_t have_differential_receiver;
/**
* Use the TX interface with D and SE0 signals instead of Dp/Dn, for use with
* certain transceivers.
*/
dif_toggle_t use_tx_d_se0;
/*
* Recognize a single SE0 bit as end of packet instead of requiring
* two bits.
*/
dif_toggle_t single_bit_eop;
/**
* Flip the D+/D- pins.
*/
dif_toggle_t pin_flip;
/**
* Reference signal generation for clock synchronization.
*/
dif_toggle_t clock_sync_signals;
} dif_usbdev_config_t;
/**
* Configures a USB device with runtime information.
*
* This function should need to be called once for the lifetime of `handle`.
*
* @param usbdev A USB device.
* @param buffer_pool A USB device buffer pool.
* @param config Runtime configuration parameters for a USB device.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_configure(const dif_usbdev_t *usbdev,
dif_usbdev_buffer_pool_t *buffer_pool,
dif_usbdev_config_t config);
/**
* Fill the available buffer FIFO of a USB device.
*
* The USB device has a small FIFO (AV FIFO) that stores free buffers for
* incoming packets. It is the responsibility of the software to ensure that the
* AV FIFO is never empty. If the host tries to send a packet when the AV FIFO
* is empty, the USB device will respond with a NAK. While this will typically
* cause the host to retry transmission for regular data packets, there are
* transactions in the USB protocol during which the USB device is not allowed
* to send a NAK. Thus, the software must make sure that the AV FIFO is never
* empty by calling this function periodically.
*
* @param usbdev A USB device.
* @param buffer_pool A USB device buffer pool.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_fill_available_fifos(
const dif_usbdev_t *usbdev, dif_usbdev_buffer_pool_t *buffer_pool);
/**
* Enable or disable reception of SETUP packets for an endpoint.
*
* This controls whether the pair of IN and OUT endpoints with the specified
* endpoint number are control endpoints.
*
* @param usbdev A USB device.
* @param endpoint An endpoint number.
* @param new_state New SETUP packet reception state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_endpoint_setup_enable(const dif_usbdev_t *usbdev,
uint8_t endpoint,
dif_toggle_t new_state);
/**
* Enable or disable reception of OUT packets for an active endpoint.
*
* When disabling reception of OUT packets, what the endpoint will do depends
* on other factors. If the endpoint is currently configured as a control
* endpoint (receives SETUP packets) or it is configured as an isochronous
* endpoint, disabling reception of OUT packets will cause them to be ignored.
*
* If the endpoint is neither a control nor isochronous endpoint, then its
* behavior depends on whether it is configured to respond with STALL. If the
* STALL response is not active, then disabling reception will cause usbdev to
* NAK the packet. Otherwise, the STALL response takes priority, regardless of
* the setting here.
*
* @param usbdev A USB device.
* @param endpoint An OUT endpoint number.
* @param new_state New OUT packet reception state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_endpoint_out_enable(const dif_usbdev_t *usbdev,
uint8_t endpoint,
dif_toggle_t new_state);
/**
* Enable or disable clearing the out_enable bit after completion of an OUT
* transaction to an endpoint.
*
* If set_nak_out is enabled, an OUT endpoint will disable reception of OUT
* packets after each successful OUT transaction to that endpoint, requiring a
* call to `dif_usbdev_endpoint_out_enable()` to enable reception again.
*
* @param usbdev A USB device.
* @param endpoint An OUT endpoint number.
* @param new_state New set_nak_on_out state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_endpoint_set_nak_out_enable(const dif_usbdev_t *usbdev,
uint8_t endpoint,
dif_toggle_t new_state);
/**
* Enable or disable STALL for an endpoint.
*
* @param usbdev A USB device.
* @param endpoint An endpoint ID.
* @param new_state New STALL state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_endpoint_stall_enable(const dif_usbdev_t *usbdev,
dif_usbdev_endpoint_id_t endpoint,
dif_toggle_t new_state);
/**
* Get STALL state of an endpoint.
*
* @param usbdev A USB device.
* @param endpoint An endpoint ID.
* @param[out] state Current STALL state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_endpoint_stall_get(const dif_usbdev_t *usbdev,
dif_usbdev_endpoint_id_t endpoint,
bool *state);
/**
* Enable or disable isochronous mode for an endpoint.
*
* Isochronous endpoints transfer data periodically. Since isochronous transfers
* do not have a handshaking stage, isochronous endpoints cannot report errors
* or STALL conditions.
*
* @param usbdev A USB device.
* @param endpoint An endpoint.
* @param new_state New isochronous state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_endpoint_iso_enable(const dif_usbdev_t *usbdev,
dif_usbdev_endpoint_id_t endpoint,
dif_toggle_t new_state);
/**
* Enable or disable an endpoint.
*
* An enabled endpoint responds to packets from the host. A disabled endpoint
* ignores them.
*
* @param usbdev A USB device.
* @param endpoint An endpoint.
* @param new_state New endpoint state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_endpoint_enable(const dif_usbdev_t *usbdev,
dif_usbdev_endpoint_id_t endpoint,
dif_toggle_t new_state);
/**
* Enable the USB interface of a USB device.
*
* Calling this function causes the USB device to assert the full-speed pull-up
* signal to indicate its presence to the host. Ensure the default endpoint is
* set up before enabling the interface.
*
* @param usbdev A USB device.
* @param new_state New interface state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_interface_enable(const dif_usbdev_t *usbdev,
dif_toggle_t new_state);
/**
* Information about a received packet.
*/
typedef struct dif_usbdev_rx_packet_info {
/**
* Endpoint of the packet.
*/
uint8_t endpoint;
/**
* Payload length in bytes.
*/
uint8_t length;
/**
* Indicates if the packet is a SETUP packet.
*/
bool is_setup;
} dif_usbdev_rx_packet_info_t;
/**
* Get the packet at the front of RX FIFO.
*
* The USB device has a small FIFO (RX FIFO) that stores received packets until
* the software has a chance to process them. It is the responsibility of the
* software to ensure that the RX FIFO is never full. If the host tries to send
* a packet when the RX FIFO is full, the USB device will respond with a NAK.
* While this will typically cause the host to retry transmission for regular
* data packets, there are transactions in the USB protocol during which the USB
* device is not allowed to send a NAK. Thus, the software must read received
* packets as soon as possible.
*
* Reading received packets involves two main steps:
* - Calling this function, i.e. `dif_usbdev_recv`, and
* - Calling `dif_usbdev_buffer_read` until the entire packet payload
* is read.
*
* In order to read an incoming packet, clients should first call this function
* to get information about the packet and the buffer that holds the packet
* payload. Then, clients should call `dif_usbdev_buffer_read` with this buffer
* one or more times (depending on the sizes of their internal buffers) until
* the entire packet payload is read. Once the entire payload is read, the
* buffer is returned to the free buffer pool. If the clients want to ignore the
* payload of a packet, e.g. for an unsupported or a zero-length packet, they
* can call `dif_usbdev_buffer_return` to immediately return the buffer to the
* free buffer pool.
*
* @param usbdev A USB device.
* @param[out] packet_info Packet information.
* @param[out] buffer Buffer that holds the packet payload.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_recv(const dif_usbdev_t *usbdev,
dif_usbdev_rx_packet_info_t *packet_info,
dif_usbdev_buffer_t *buffer);
/**
* Read incoming packet payload.
*
* Clients should call this function with a buffer provided by `dif_usbdev_recv`
* to read the payload of an incoming packet. This function copies the smaller
* of `dst_len` and remaining number of bytes in the buffer to `dst`. The buffer
* that holds the packet payload is returned to the free buffer pool when the
* entire packet payload is read.
*
* See also: `dif_usbdev_recv`.
*
* @param usbdev A USB device.
* @param buffer_pool A USB device buffer pool.
* @param buffer A buffer provided by `dif_usbdev_recv`.
* @param[out] dst Destination buffer.
* @param dst_len Length of the destination buffer.
* @param[out] bytes_written Number of bytes written to destination buffer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_read(const dif_usbdev_t *usbdev,
dif_usbdev_buffer_pool_t *buffer_pool,
dif_usbdev_buffer_t *buffer, uint8_t *dst,
size_t dst_len, size_t *bytes_written);
/**
* Return a buffer to the free buffer pool.
*
* This function immediately returns the given buffer to the free buffer pool.
* Since `dif_usbdev_buffer_read` and `dif_usbdev_get_tx_status` return the
* buffers that they work on to the free buffer pool automatically, this
* function should only be called to discard the payload of a received
* packet or a packet that was being prepared for transmission before it is
* queued for transmission from an endpoint.
*
* See also: `dif_usbdev_recv`, `dif_usbdev_buffer_request`.
*
* @param usbdev A USB device.
* @param buffer_pool A USB device buffer pool.
* @param buffer A buffer provided by `dif_usbdev_recv` or
* `dif_usbdev_buffer_request`.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_return(const dif_usbdev_t *usbdev,
dif_usbdev_buffer_pool_t *buffer_pool,
dif_usbdev_buffer_t *buffer);
/**
* Request a buffer for outgoing packet payload.
*
* Clients should call this function to request a buffer to write the payload of
* an outgoing packet. Sending a packet from a particular endpoint to the host
* involves four main steps:
* - Calling this function, i.e. `dif_usbdev_buffer_request`,
* - Calling `dif_usbdev_buffer_write`,
* - Calling `dif_usbdev_send`, and
* - Calling `dif_usbdev_get_tx_status`.
*
* In order to send a packet, clients should first call this function to obtain
* a buffer for the packet payload. Clients should then call
* `dif_usbdev_buffer_write` (one or more times depending on the sizes of their
* internal buffers) to write the packet payload to this buffer. After writing
* the packet payload, clients should call `dif_usbdev_send` to mark the packet
* as ready for transmission from a particular endpoint. Then, clients should
* call `dif_usbdev_get_tx_status` to check the status of the transmission.
* `dif_usbdev_get_tx_status` returns the buffer that holds the packet payload
* to the free buffer pool once the packet is either successfully transmitted or
* canceled due to an incoming SETUP packet or a link reset. If the packet
* should no longer be sent, clients can call `dif_usbdev_buffer_return` to
* return the buffer to the free buffer pool as long as `dif_usbdev_send` is not
* called yet.
*
* See also: `dif_usbdev_buffer_write`, `dif_usbdev_send`,
* `dif_usbdev_get_tx_status`, `dif_usbdev_buffer_return`.
*
* @param usbdev A USB device.
* @param buffer_pool A USB device buffer pool.
* @param[out] buffer A buffer for writing outgoing packet payload.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_request(const dif_usbdev_t *usbdev,
dif_usbdev_buffer_pool_t *buffer_pool,
dif_usbdev_buffer_t *buffer);
/**
* Write outgoing packet payload.
*
* Clients should call this function with a buffer provided by
* `dif_usbdev_buffer_request` to write the payload of an outgoing packet. This
* function copies the smaller of `src_len` and remaining number of bytes in the
* buffer to the buffer. Clients should then call `dif_usbdev_send` to queue the
* packet for transmission from a particular endpoint.
*
* See also: `dif_usbdev_buffer_request`, `dif_usbdev_send`,
* `dif_usbdev_get_tx_status`, `dif_usbdev_buffer_return`.
*
* @param usbdev A USB device.
* @param buffer A buffer provided by `dif_usbdev_buffer_request`.
* @param src Source buffer.
* @param src_len Length of the source buffer.
* @param[out] bytes_written Number of bytes written to the USB device buffer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_write(const dif_usbdev_t *usbdev,
dif_usbdev_buffer_t *buffer,
const uint8_t *src, size_t src_len,
size_t *bytes_written);
/**
* Mark a packet ready for transmission from an endpoint.
*
* The USB device has 12 endpoints, each of which can be used to send packets to
* the host. Since a packet is not actually transmitted to the host until the
* host sends an IN token, clients must write the packet payload to a device
* buffer and mark it as ready for transmission from a particular endpoint. A
* packet queued for transmission from a particular endpoint is transmitted once
* the host sends an IN token for that endpoint.
*
* After a packet is queued for transmission, clients should check its status by
* calling `dif_usbdev_get_tx_status`. While the USB device handles transmission
* errors automatically by retrying transmission, transmission of a packet may
* be canceled if the endpoint receives a SETUP packet or the link is reset
* before the queued packet is transmitted. In these cases, clients should
* handle the SETUP packet or the link reset first and then optionally send the
* same packet again. Clients must also make sure that the given endpoint does
* not already have a packet pending for transmission before calling this
* function.
*
* See also: `dif_usbdev_buffer_request`, `dif_usbdev_buffer_write`,
* `dif_usbdev_get_tx_status`, `dif_usbdev_buffer_return`.
*
* @param usbdev A USB device.
* @param endpoint An OUT endpoint number.
* @param buffer A buffer provided by `dif_usbdev_buffer_request`.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_send(const dif_usbdev_t *usbdev, uint8_t endpoint,
dif_usbdev_buffer_t *buffer);
/**
* Get which IN endpoints have sent packets.
*
* This function provides which endpoints have buffers that have successfully
* completed transmission to the host. It may be used to guide calls to
* `dif_usbdev_clear_tx_status` to return the used buffer to the pool and clear
* the state for the next transaction.
*
* @param usbdev A USB device.
* @param[out] sent A bitmap of which endpoints have sent packets.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_get_tx_sent(const dif_usbdev_t *usbdev, uint16_t *sent);
/**
* Clear the TX state of the provided endpoint and restore its associated buffer
* to the pool.
*
* Note that this function should only be called when an endpoint has been
* provided a buffer. Without it, the buffer pool will become corrupted, as this
* function does not check the status.
*
* In addition, if the endpoint has not yet completed or canceled the
* transaction, the user must not call this function while the device is in an
* active state. Otherwise, the user risks corrupting an ongoing transaction.
*
* @param usbdev A USB device.
* @param buffer_pool A USB device buffer pool.
* @param endpoint An IN endpoint number.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_clear_tx_status(const dif_usbdev_t *usbdev,
dif_usbdev_buffer_pool_t *buffer_pool,
uint8_t endpoint);
/**
* Status of an outgoing packet.
*/
typedef enum dif_usbdev_tx_status {
/**
* There is no packet for the given OUT endpoint.
*/
kDifUsbdevTxStatusNoPacket,
/**
* Packet is pending transmission.
*/
kDifUsbdevTxStatusPending,
/**
* Packet was sent successfully.
*/
kDifUsbdevTxStatusSent,
/**
* Transmission was canceled due to an incoming SETUP packet.
*/
kDifUsbdevTxStatusCancelled,
} dif_usbdev_tx_status_t;
/**
* Get the status of a packet that has been queued to be sent from an endpoint.
*
* While the USB device handles transmission errors automatically by retrying
* transmission, transmission of a packet may be canceled if the endpoint
* receives a SETUP packet or the link is reset before the queued packet is
* transmitted. In these cases, clients should handle the SETUP packet or the
* link reset first and then optionally send the same packet again.
*
* This function does not modify any device state. `dif_usbdev_clear_tx_status`
* can be used to clear the status and return the buffer to the pool.
*
* @param usbdev A USB device.
* @param endpoint An IN endpoint number.
* @param[out] status Status of the packet.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_get_tx_status(const dif_usbdev_t *usbdev,
uint8_t endpoint,
dif_usbdev_tx_status_t *status);
/**
* Set the address of a USB device.
*
* @param usbdev A USB device.
* @param addr New address. Only the last 7 bits are significant.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_address_set(const dif_usbdev_t *usbdev, uint8_t addr);
/**
* Get the address of a USB device.
*
* @param usbdev A USB device.
* @param[out] addr Current address.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_address_get(const dif_usbdev_t *usbdev, uint8_t *addr);
/**
* Read the data toggle bits of the OUT endpoints.
*
* @param usbdev A USB device.
* @param[out]toggles Current state of OUT data toggle bits.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_data_toggle_out_read(const dif_usbdev_t *usbdev,
uint16_t *toggles);
/**
* Read the data toggle bits of the IN endpoints.
*
* @param usbdev A USB device.
* @param[out]toggles Current state of IN data toggle bits.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_data_toggle_in_read(const dif_usbdev_t *usbdev,
uint16_t *toggles);
/**
* Write to the data toggle bits of a subset of the OUT endpoints.
* Set 1 in `mask` to change the data toggle bit of an OUT endpoint to the value
* of the corresponding bit in `state`.
*
* @param usbdev A USB device.
* @param mask Mask of OUT endpoint data toggles to be changed.
* @param state New states of that OUT endpoint data toggles being changed.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_data_toggle_out_write(const dif_usbdev_t *usbdev,
uint16_t mask, uint16_t state);
/**
* Write to the data toggle bits of a subset of the IN endpoints.
* Set 1 in `mask` to change the data toggle bit of an IN endpoint to the value
* of the corresponding bit in `state`.
*
* @param usbdev A USB device.
* @param mask Mask of IN endpoint data toggles to be changed.
* @param state New states of that IN endpoint data toggles being changed.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_data_toggle_in_write(const dif_usbdev_t *usbdev,
uint16_t mask, uint16_t state);
/**
* Clear the data toggle bits for the selected endpoint.
*
* @param usbdev A USB device.
* @param endpoint An endpoint number.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_clear_data_toggle(const dif_usbdev_t *usbdev,
uint8_t endpoint);
/**
* Get USB frame index.
*
* @param usbdev A USB device.
* @param[out] frame_index USB frame index.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_frame(const dif_usbdev_t *usbdev,
uint16_t *frame_index);
/**
* Check if the host is lost.
*
* The host is lost if the link is still active but a start of frame packet has
* not been received in the last 4.096ms.
*
* @param usbdev A USB device.
* @param[out] host_lost Status of the host. `true` if the host is lost, `false`
* otherwise.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_host_lost(const dif_usbdev_t *usbdev,
bool *host_lost);
/**
* USB link state.
*/
typedef enum dif_usbdev_link_state {
kDifUsbdevLinkStateDisconnected,
kDifUsbdevLinkStatePowered,
kDifUsbdevLinkStatePoweredSuspended,
kDifUsbdevLinkStateActive,
kDifUsbdevLinkStateSuspended,
kDifUsbdevLinkStateActiveNoSof,
kDifUsbdevLinkStateResuming,
} dif_usbdev_link_state_t;
/**
* Get USB link state.
*
* @param usbdev A USB device.
* @param[out] link_state USB link state.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_link_state(
const dif_usbdev_t *usbdev, dif_usbdev_link_state_t *link_state);
/**
* Get the state of the sense pin.
*
* @param usbdev A USB device.
* @param[out] sense State of the sense pin. `true` if the host is providing
* VBUS, `false` otherwise.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_sense(const dif_usbdev_t *usbdev,
bool *sense);
/**
* Get the depths of the AV OUT and AV SETUP FIFOs.
*
* See also: `dif_usbdev_fill_available_fifos`.
*
* @param usbdev A USB device.
* @param[out] setup_depth Depth of the AV SETUP FIFO.
* @param[out] out_depth Depth of the AV OUT FIFO.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_available_fifo_depths(
const dif_usbdev_t *usbdev, uint8_t *setup_depth, uint8_t *out_depth);
/**
* Check if AV OUT and AV SETUP FIFOs are full.
*
* See also: `dif_usbdev_fill_available_fifos`.
*
* @param usbdev A USB device.
* @param[out] setup_is_full State of the AV SETUP FIFO. `true` if full, false
* otherwise.
* @param[out] out_is_full State of the AV OUT FIFO. `true` if full, false
* otherwise.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_available_fifo_full(
const dif_usbdev_t *usbdev, bool *setup_is_full, bool *out_is_full);
/**
* Get the depth of the RX FIFO.
*
* See also: `dif_usbdev_recv`.
*
* @param usbdev A USB device.
* @param[out] depth Depth of the RX FIFO.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_rx_fifo_depth(const dif_usbdev_t *usbdev,
uint8_t *depth);
/**
* Check if the RX FIFO is empty.
*
* See also: `dif_usbdev_recv`.
*
* @param usbdev A USB device.
* @param[out] is_empty State of the RX FIFO. `true` if empty, `false`
* otherwise.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_status_get_rx_fifo_empty(const dif_usbdev_t *usbdev,
bool *is_empty);
/**
* Control whether oscillator test mode is enabled.
*
* In oscillator test mode, usbdev transmits a continuous 0101 pattern for
* evaluating the reference clock's quality.
*
* @param usbdev A USB device.
* @param enable Whether the test mode should be enabled.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_set_osc_test_mode(const dif_usbdev_t *usbdev,
dif_toggle_t enable);
/**
* Control whether the AON wake module is active.
*
* @param usbdev A USB device.
* @param enable Whether the AON wake module is enabled.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_set_wake_enable(const dif_usbdev_t *usbdev,
dif_toggle_t enable);
typedef struct dif_usbdev_wake_status {
/** Whether the AON wake module is active. */
bool active;
/** Whether the USB disconnected while the AON wake module was active. */
bool disconnected;
/** Whether the USB was reset while the AON wake module was active. */
bool bus_reset;
} dif_usbdev_wake_status_t;
/**
* Get the status of the AON wake module.
*
* Note that the conditions triggering exit from suspended state must be read
* before disabling the AON wake module. Once the AON wake module is
* deactivated, that status information is lost.
*
* Also note that the ordinary resume condition does not report to the usbdev
* module. Instead, it should be obtained from the module monitoring wakeup
* sources.
*
* @param usbdev A USB device.
* @param[out] status The status of the module.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_get_wake_status(const dif_usbdev_t *usbdev,
dif_usbdev_wake_status_t *status);
/**
* Force the link state machine to resume to an active state.
*
* This is used when waking from a low-power suspended state to resume to an
* active state. It moves the usbdev out of the Powered state (from the USB
* device state machine in the spec) without receiving a bus reset. Without help
* from software, the usbdev module cannot determine on its own when a bus reset
* is required.
*
* @param usbdev A USB device.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_resume_link_to_active(const dif_usbdev_t *usbdev);
typedef struct dif_usbdev_phy_pins_sense {
/** USB D+ input. */
bool rx_dp : 1;
/** USB D- input. */
bool rx_dn : 1;
/** USB data input from an external differential receiver, if available. */
bool rx_d : 1;
/** USB transmit D+ output. */
bool tx_dp : 1;
/** USB transmit D- output. */
bool tx_dn : 1;
/** USB transmit data value output. */
bool tx_d : 1;
/** USB single-ended zero output. */
bool tx_se0 : 1;
/** USB output enable for D+ / D-. */
bool output_enable : 1;
/** USB VBUS sense pin. */
bool vbus_sense : 1;
} dif_usbdev_phy_pins_sense_t;
/**
* Get the current state of the USB PHY pins.
*
* @param usbdev A USB device.
* @param[out] status The current state of the pins.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_get_phy_pins_status(
const dif_usbdev_t *usbdev, dif_usbdev_phy_pins_sense_t *status);
typedef struct dif_usbdev_phy_pins_drive {
/** USB D+ output, for use with dn. */
bool dp : 1;
/** USB D- output. for use with dp. */
bool dn : 1;
/** USB data output, encoding K and J when se0 is 0. */
bool data : 1;
/** USB single-ended zero output. */
bool se0 : 1;
/** USB output enable for D+ / D-. */
bool output_enable : 1;
/** Enable control pin for the differential receiver. */
bool diff_receiver_enable : 1;
/** Controls whether to pull up the D+ pin. */
bool dp_pullup_en : 1;
/** Controls whether to pull up the D- pin. */
bool dn_pullup_en : 1;
} dif_usbdev_phy_pins_drive_t;
/**
* Control whether to override the USB PHY and drive pins as GPIOs.
*
* @param usbdev A USB device.
* @param override_enable Enable / disable the GPIO-like overrides.
* @param overrides The values to set the pins to.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_set_phy_pins_state(
const dif_usbdev_t *usbdev, dif_toggle_t override_enable,
dif_usbdev_phy_pins_drive_t overrides);
/**
* Raw data transfer directly to the packet buffer memory. This is a faster
* implementation of the generic `mmio_memcpy_to_mmio32` that is specialized for
* the USB device and gives a significant performance improvement.
*
* @param usbdev A USB device.
* @param id Buffer number.
* @param src Source data.
* @param src_len Number of bytes to transfer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_raw_write(const dif_usbdev_t *usbdev, uint8_t id,
const uint8_t *src, size_t src_len);
/**
* Raw data transfer directly from the packet buffer memory. This is a faster
* implementation of the generic `mmio_memcpy_from_mmio32` that is specialized
* for the USB device and gives a significant performance improvemenet.
*
* @param usbdev A USB device.
* @param id Buffer number.
* @param dst Destination buffer.
* @param dst_len Number of bytes to transfer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_raw_read(const dif_usbdev_t *usbdev, uint8_t id,
uint8_t *dst, size_t dst_len);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_USBDEV_H_