CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
platform-usbdev.hh
1// SPDX-FileCopyrightText: CHERIoT contributors
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5#include <cdefs.h>
6#include <optional>
7#include <stdint.h>
8#include <utils.hh>
9
10/**
11 * A driver for OpenTitan USB Device, which is used in the Sonata system.
12 *
13 * This peripheral's source and documentation can be found at:
14 * https://github.com/lowRISC/opentitan/tree/ab878b5d3578939a04db72d4ed966a56a869b2ed/hw/ip/usbdev
15 *
16 * With rendered register documentation served at:
17 * https://opentitan.org/book/hw/ip/usbdev/doc/registers.html
18 *
19 * An incredibly brief overview of how the USB device and it's buffers:
20 * Data packet ingress and egress goes via a pool of 64 byte buffers living
21 * in a 2kB SRAM packet buffer, which is accessable as a large MMIO region.
22 * The software manages these buffers using buffer IDs as references.
23 * IDs are pushed or popped into different FIFOs by either the software or
24 * device depending on whether they contain a packet to be sent, are available
25 * for a packet to be received into them, or contain a packet that has been
26 * received.
27 *
28 * See https://opentitan.org/book/hw/ip/usbdev/doc/programmers_guide.html for
29 * more information.
30 */
32{
33 public:
34 /// Supported sizes for the USB Device.
35 static constexpr uint8_t MaxPacketLength = 64u;
36 static constexpr uint8_t BufferCount = 32u;
37 static constexpr uint8_t MaxEndpoints = 12u;
38
39 /**
40 * The offset from the start of the USB Device MMIO region at which
41 * packet buffer memory begins.
42 */
43 static constexpr uint32_t BufferStartAddress = 0x800u;
44
45 /// Device Registers
47 uint32_t interruptEnable;
48 uint32_t interruptTest;
49 uint32_t alertTest;
50 uint32_t usbControl;
51 uint32_t endpointOutEnable;
52 uint32_t endpointInEnable;
53 uint32_t usbStatus;
54 uint32_t availableOutBuffer;
55 uint32_t availableSetupBuffer;
56 uint32_t receiveBuffer;
57 /// Register to enable receive SETUP transactions
59 /// Register to enable receive OUT transactions
61 /// Register to set NAK (Not/Negated Acknowledge) after OUT transactions
63 /// Register showing ACK receival to indicate a successful IN send
64 uint32_t inSent;
65 /// Registers for controlling the stalling of OUT and IN endpoints
66 uint32_t outStall;
67 uint32_t inStall;
68 /**
69 * IN transaction configuration registers. There is one register per
70 * endpoint for the USB device.
71 */
72 uint32_t configIn[MaxEndpoints];
73 /**
74 * Registers for configuring which endpoints should be treated as
75 * isochronous endpoints. This means that if the corresponding bit is set,
76 * then that no handshake packet will be sent for an OUT/IN transaction on
77 * that endpoint.
78 */
80 uint32_t inIsochronous;
81 /// Registers for configuring if endpoints data toggle on transactions
82 uint32_t outDataToggle;
83 uint32_t inDataToggle;
84
85 private:
86 /**
87 * Registers to sense/drive the USB PHY pins. That is, these registers can
88 * be used to respectively read out the state of the USB device inputs and
89 * outputs, or to control the inputs and outputs from software. These
90 * registers are kept private as they are intended to be used for debugging
91 * purposes or during chip testing, and not in actual software.
92 */
93 [[maybe_unused]] uint32_t phyPinsSense;
94 [[maybe_unused]] uint32_t phyPinsDrive;
95
96 public:
97 /// Config register for the USB PHY pins.
98 uint32_t phyConfig;
99
100 /// Interrupt definitions for OpenTitan's USB Device.
101 enum class UsbdevInterrupt : uint32_t
102 {
103 /// Interrupt asserted whilst the receive FIFO (buffer) is not empty.
104 PacketReceived = 1u << 0,
105 /**
106 * Interrupt asserted when a packet was sent as part of an IN
107 * transaction, but not cleared from the `inSent` register.
108 */
109 PacketSent = 1u << 1,
110 /**
111 * Interrupt raised when VBUS (power supply) is lost, i.e. the link to
112 * the USB host controller has been disconnected.
113 */
114 Disconnected = 1u << 2,
115 /**
116 * Interrupt raised when the link is active, but a Start of Frame (SOF)
117 * packet has not been received within a given timeout threshold, which
118 * is set to 4.096 milliseconds.
119 */
120 HostLost = 1u << 3,
121 /**
122 * Interrupt raised when a Bus Reset condition is indicated on the link
123 * by the link being held in an SE0 state (Single Ended Zero, both lines
124 * being pulled low) for longer than 3 microseconds.
125 */
126 LinkReset = 1u << 4,
127 /**
128 * Interrupt raised when the link has entered the suspend state, due to
129 * being idle for more than 3 milliseconds.
130 */
131 LinkSuspend = 1u << 5,
132 /// Interrupt raised on link transition from suspended to non-idle.
133 LinkResume = 1u << 6,
134 /// Interrupt asserted whilst the Available OUT buffer is empty.
136 /// Interrupt asserted whilst the Receive buffer is full.
137 ReceiveFull = 1u << 8,
138 /**
139 * Interrupt raised when the Available OUT buffer or the Available SETUP
140 * buffer overflows.
141 */
143 /// Interrupt raised when an error occurs during an IN transaction.
144 LinkInError = 1u << 10,
145 /**
146 * Interrupt raised when a CRC (cyclic redundancy check) error occurs on
147 * a received packet; i.e. there was an error in transmission.
148 */
150 /// Interrupt raised when an invalid Packet Identifier is received.
152 /// Interrupt raised when a bit stuffing violation is detected.
154 /**
155 * Interrupt raised when the USB frame number is updated with a valid
156 * SOF (Start of Frame) packet.
157 */
158 FrameUpdated = 1u << 14,
159 /// Interrupt raised when VBUS (power supply) is detected.
160 Powered = 1u << 15,
161 /// Interrupt raised when an error occurs during an OUT transaction.
162 LinkOutError = 1u << 16,
163 /// Interrupt asserted whilst the Available SETUP buffer is empty.
165 };
166
167 /**
168 * Definitions of fields (and their locations) for the USB Control register
169 * (offset 0x10).
170 *
171 * https://opentitan.org/book/hw/ip/usbdev/doc/registers.html#usbctrl
172 */
173 enum class UsbControlField : uint32_t
174 {
175 Enable = 1u << 0,
176 ResumeLinkActive = 1u << 1,
177 DeviceAddress = 0x7Fu << 16,
178 };
179
180 /**
181 * Definitions of fields (and their locations) for the USB Status register
182 * (offset 0x1c).
183 *
184 * https://opentitan.org/book/hw/ip/usbdev/doc/registers.html#usbstat
185 */
186 enum class UsbStatusField : uint32_t
187 {
188 Frame = 0x7FFu << 0,
189 HostLost = 1u << 11,
190 LinkState = 0x7u << 12,
191 Sense = 1u << 15,
192 AvailableOutDepth = 0xFu << 16,
193 AvailableSetupDepth = 0x7u << 20,
194 AvailableOutFull = 1u << 23,
195 ReceiveDepth = 0xFu << 24,
196 AvailableSetupFull = 1u << 30,
197 ReceiveEmpty = 1u << 31,
198 };
199
200 /**
201 * Definitions of fields (and their locations) for the Receive FIFO
202 * buffer register (offset 0x28).
203 *
204 * https://opentitan.org/book/hw/ip/usbdev/doc/registers.html#rxfifo
205 */
206 enum class ReceiveBufferField : uint32_t
207 {
208 BufferId = 0x1Fu << 0,
209 Size = 0x7Fu << 8,
210 Setup = 1u << 19,
211 EndpointId = 0xFu << 20,
212 };
213
214 /**
215 * Definitions of fields (and their locations) for a Config In register
216 * (where there is one such register for each endpoint). These are
217 * the registers with offsets 0x44 up to (and not including) 0x74.
218 *
219 * https://opentitan.org/book/hw/ip/usbdev/doc/registers.html#configin
220 */
221 enum class ConfigInField : uint32_t
222 {
223 BufferId = 0x1Fu << 0,
224 Size = 0x7Fu << 8,
225 Sending = 1u << 29,
226 Pending = 1u << 30,
227 Ready = 1u << 31,
228 };
229
230 /**
231 * Definitions of fields (and their locations) for the PHY Config
232 * Register (offset 0x8c).
233 *
234 * https://opentitan.org/book/hw/ip/usbdev/doc/registers.html#phy_config
235 */
236 enum class PhyConfigField : uint32_t
237 {
238 UseDifferentialReceiver = 1u << 0,
239 // Other PHY Configuration fields are omitted.
240 };
241
242 /**
243 * Ensure that the Available OUT and Available SETUP buffers are kept
244 * supplied with buffers for packet reception.
245 *
246 * @param bufferBitmap A bitmap of the buffers that are not currently
247 * committed (where 1 corresponds to not in use).
248 * @returns The updated bitmap after supplying buffers.
249 */
250 [[nodiscard]] uint64_t supply_buffers(uint64_t bufferBitmap) volatile
251 {
252 constexpr uint32_t SetupFullBit =
253 static_cast<uint32_t>(UsbStatusField::AvailableSetupFull);
254 constexpr uint32_t OutFullBit =
255 static_cast<uint32_t>(UsbStatusField::AvailableOutFull);
256
257 for (uint8_t index = 0; index < BufferCount; index++)
258 {
259 const uint32_t Buffer = (1u << index);
260 if (!(bufferBitmap & Buffer))
261 {
262 continue; // Skip buffers that are not available
263 }
264
265 // If a buffer is available, and either Available SETUP or OUT are
266 // not yet full, then commit that buffer and mark it as in use.
267 if (usbStatus & SetupFullBit)
268 {
269 if (usbStatus & OutFullBit)
270 {
271 break; // Both are full - stop trying to supply buffers.
272 }
273 availableOutBuffer = index;
274 }
275 else
276 {
277 availableSetupBuffer = index;
278 }
279 bufferBitmap &= ~Buffer;
280 }
281 return bufferBitmap;
282 }
283
284 /**
285 * Enable a specified interrupt / interrupts.
286 */
287 void interrupt_enable(UsbdevInterrupt interrupt) volatile
288 {
289 interruptEnable = interruptEnable | static_cast<uint32_t>(interrupt);
290 }
291
292 /**
293 * Disable a specified interrupt / interrupts.
294 */
295 void interrupt_disable(UsbdevInterrupt interrupt) volatile
296 {
297 interruptEnable = interruptEnable & ~static_cast<uint32_t>(interrupt);
298 }
299
300 /**
301 * Initialise the USB device, ensuring that packet buffers are available for
302 * reception and that the PHY has been appropriately configured. Note that
303 * at this stage, endpoints have not been configured and the device has not
304 * been connected to the USB.
305 *
306 * @param bufferBitmap An out-parameter, to initialise a bitmap of the
307 * buffers that are not currently commited (1 corresponds to not in use).
308 *
309 * @returns 0 if initialisation is sucessful, and non-zero otherwise.
310 */
311 [[nodiscard]] int init(uint64_t &bufferBitmap) volatile
312 {
313 bufferBitmap =
314 supply_buffers((static_cast<uint64_t>(1u) << BufferCount) - 1u);
315 phyConfig =
316 static_cast<uint32_t>(PhyConfigField::UseDifferentialReceiver);
317 return 0;
318 }
319
320 /**
321 * Set up the configuration of an OUT endpoint for the USB device.
322 *
323 * @param endpointId The ID of the OUT endpoint to configure.
324 * @param enabled Whether the OUT endpoint should be enabled or not.
325 * @param setup Whether SETUP transactions should be enabled for the
326 * endpoint.
327 * @param isochronous Whether the endpoint should operate isochronously or
328 * non-isochronously.
329 *
330 * @returns 0 if configuration is successful, and non-zero otherwise.
331 */
332 [[nodiscard]] int out_endpoint_configure(uint8_t endpointId,
333 bool enabled,
334 bool setup,
335 bool isochronous) volatile
336 {
337 if (endpointId >= MaxEndpoints)
338 {
339 return -1;
340 }
341 const uint32_t Mask = 1u << endpointId;
342 endpointOutEnable = (endpointOutEnable & ~Mask) | (enabled ? Mask : 0u);
343 outIsochronous = (outIsochronous & ~Mask) | (isochronous ? Mask : 0u);
344 receiveEnableSetup = (receiveEnableSetup & ~Mask) | (setup ? Mask : 0u);
345 receiveEnableOut = (receiveEnableOut & ~Mask) | (enabled ? Mask : 0u);
346 return 0;
347 }
348
349 /**
350 * Set up the configuration of an IN endpoint for the USB device.
351 *
352 * @param endpointId The ID of the IN endpoint to configure
353 * @param enabled Whether the IN endpoint should be enabled or not.
354 * @param isochronous Whether the endpoint should operate isochronously or
355 * non-isochronously.
356 *
357 * @returns 0 if configuration is successful, and non-zero otherwise.
358 */
359 [[nodiscard]] int in_endpoint_configure(uint8_t endpointId,
360 bool enabled,
361 bool isochronous) volatile
362 {
363 if (endpointId >= MaxEndpoints)
364 {
365 return -1;
366 }
367 const uint32_t Mask = 1u << endpointId;
368 endpointInEnable = (endpointInEnable & ~Mask) | (enabled ? Mask : 0u);
369 inIsochronous = (inIsochronous & ~Mask) | (isochronous ? Mask : 0u);
370 return 0;
371 }
372
373 /**
374 * Set the STALL state of a specified endpoint pair (both IN and OUT).
375 *
376 * @param endpointId The ID of the endpoint pair to modify.
377 * @param stalling Whether the endpoints are stalling or not.
378 *
379 * @returns 0 if successful, and non-zero otherwise.
380 */
381 [[nodiscard]] int endpoint_stalling_set(uint8_t endpointId,
382 bool stalling) volatile
383 {
384 if (endpointId >= MaxEndpoints)
385 {
386 return -1;
387 }
388 const uint32_t Mask = 1u << endpointId;
389 outStall = (outStall & ~Mask) | (stalling ? Mask : 0u);
390 inStall = (inStall & ~Mask) | (stalling ? Mask : 0u);
391 return 0;
392 }
393
394 /**
395 * Connect the device to the USB, indicating its presence to the USB host
396 * controller. Endpoints must already have been configured at this point
397 * because traffic may be received imminently.
398 *
399 * @returns 0 if successful, and non-zero otherwise.
400 * @returns -1 if endpoint 0 isn't enabled,
401 * suggesting the endpoints haven't been configured.
402 */
403 [[nodiscard]] int connect() volatile
404 {
405 if (!(endpointInEnable & endpointOutEnable & 0b1))
406 {
407 return -1;
408 }
409 usbControl =
410 usbControl | static_cast<uint32_t>(UsbControlField::Enable);
411 return 0;
412 }
413
414 /**
415 * Disconnect the device from the USB.
416 *
417 * @returns 0 if successful, and non-zero otherwise.
418 */
419 void disconnect() volatile
420 {
421 usbControl =
422 usbControl & ~static_cast<uint32_t>(UsbControlField::Enable);
423 }
424
425 /**
426 * Check whether the USB device is connected (i.e. pullup enabled).
427 *
428 * @returns True to indicate it is connected, and false otherwise.
429 */
430 [[nodiscard]] bool connected() volatile
431 {
432 return (usbControl & static_cast<uint32_t>(UsbControlField::Enable));
433 }
434
435 /**
436 * Set the device address on the USB; this address will have been supplied
437 * by the USB host controller in the standard `SET_ADDRESS` Control
438 * Transfer.
439 *
440 * @param address The device address to set on the USB.
441 *
442 * @returns 0 if successful, and non-zero otherwise.
443 */
444 [[nodiscard]] int device_address_set(uint8_t address) volatile
445 {
446 if (address >= 0x80)
447 {
448 return -1; // Device addresses are only 7 bits long.
449 }
450 constexpr uint32_t Mask =
451 static_cast<uint32_t>(UsbControlField::DeviceAddress);
452 usbControl = (usbControl & ~Mask) | (address << 16);
453 return 0;
454 }
455
456 /**
457 * Check and retrieve the endpoint and buffer numbers of a
458 * recently-collected IN data packet. The caller is responsible for reusing
459 * or releasing the buffer.
460 *
461 * @param endpointId An out-parameter, to which the ID of the endpoint for
462 * a recently-collected IN data packet will be written.
463 * @param bufferId An out-parameter, to which the ID of the buffer for a
464 * recently-collected IN data packet will be written.
465 *
466 * @returns 0 if successful, and non-zero otherwise.
467 */
468 [[nodiscard]] int retrieve_collected_packet(uint8_t &endpointId,
469 uint8_t &bufferId) volatile
470 {
471 constexpr uint32_t BufferIdMask =
472 static_cast<uint32_t>(ConfigInField::BufferId);
473 uint32_t sent = inSent;
474
475 // Clear the first encountered packet sent indication.
476 for (endpointId = 0; endpointId < MaxEndpoints; endpointId++)
477 {
478 const uint32_t EndpointBit = 1u << endpointId;
479 if (sent & EndpointBit)
480 {
481 // Clear the `in_sent` bit for this specific endpoint, and
482 // indicate which buffer has been released.
483 inSent = EndpointBit;
484 bufferId = (configIn[endpointId] & BufferIdMask);
485 return 0;
486 }
487 }
488
489 // If no packet sent indications were found, then fail.
490 return -1;
491 }
492
493 /**
494 * Present a packet on the specified IN endpoint for collection by the USB
495 * host controller.
496 *
497 * @param bufferId The buffer to use to store the packet.
498 * @param endpointId The IN endpoint used to send the packet.
499 * @param data The packet to be transmitted.
500 * @param size The size of the packet.
501 */
502 void packet_send(uint8_t bufferId,
503 uint8_t endpointId,
504 const uint32_t *data,
505 uint8_t size) volatile
506 {
507 // Transmission of zero length packets is common over USB
508 if (size > 0)
509 {
510 usbdev_transfer(buffer(bufferId), data, size, true);
511 }
512
513 constexpr uint32_t ReadyBit =
514 static_cast<uint32_t>(ConfigInField::Ready);
515 configIn[endpointId] = bufferId | (size << 8);
516 configIn[endpointId] = configIn[endpointId] | ReadyBit;
517 }
518
519 /// The information associated with a received packet
521 {
522 uint32_t info;
523 /// The endpoint ID the received packet was received on
524 constexpr uint8_t endpoint_id()
525 {
526 return (info &
527 static_cast<uint32_t>(ReceiveBufferField::EndpointId)) >>
528 20;
529 }
530 /// The size of the received packet
531 constexpr uint16_t size()
532 {
533 return (info & static_cast<uint32_t>(ReceiveBufferField::Size)) >>
534 8;
535 }
536 /// Whether the received packet was a setup packet
537 constexpr bool is_setup()
538 {
539 return (info & static_cast<uint32_t>(ReceiveBufferField::Setup)) !=
540 0;
541 }
542 /// The buffer ID used to store the received packet
543 constexpr uint8_t buffer_id()
544 {
545 return (info &
546 static_cast<uint32_t>(ReceiveBufferField::BufferId)) >>
547 0;
548 }
549 };
550
551 /**
552 * If a packet has been received, removes the packet's buffer from the
553 * receive FIFO giving it's information and ownership to the user.
554 *
555 * `packet_data_get` can be used to retrieve the packet's data.
556 *
557 * @returns Information about the received packet, if a packet had been
558 * received.
559 */
560 [[nodiscard]] std::optional<ReceiveBufferInfo> packet_take() volatile
561 {
562 if (!(usbStatus & static_cast<uint32_t>(UsbStatusField::ReceiveDepth)))
563 {
564 return {}; // No packets received
565 }
566 return ReceiveBufferInfo{receiveBuffer};
567 }
568
569 /**
570 * Retrieves the data from a buffer containing a received packet.
571 *
572 * @param destination A destination buffer to read the packet's data into.
573 */
575 uint32_t *destination) volatile
576 {
577 const auto [id, size] =
578 std::pair{bufferInfo.buffer_id(), bufferInfo.size()};
579 // Reception of Zero Length Packets occurs in the Status Stage of IN
580 // Control Transfers.
581 if (size > 0)
582 {
583 usbdev_transfer(destination, buffer(id), size, false);
584 }
585 }
586
587 private:
588 /**
589 * Return a pointer to the given offset within the USB device register
590 * space; this is used to access the packet buffer memory.
591 *
592 * @param bufferId The buffer number to access the packet buffer memory for
593 *
594 * @returns A pointer to the buffer's memory.
595 */
596 uint32_t *buffer(uint8_t bufferId) volatile
597 {
598 const uint32_t Offset = BufferStartAddress + bufferId * MaxPacketLength;
599 const uintptr_t Address = reinterpret_cast<uintptr_t>(this) + Offset;
600 return const_cast<uint32_t *>(reinterpret_cast<uint32_t *>(Address));
601 }
602
603 /**
604 * Perform a transfer to or from packet buffer memory. This function is
605 * hand-optimised to perform a faster, unrolled, word-based data transfer
606 * for efficiency.
607 *
608 * @param destination A pointer to transfer the source data to.
609 * @param source A pointer to the data to be transferred.
610 * @param size The size of the data pointed to by `source`.
611 * @param toDevice True if the transfer is to the device (e.g. when sending
612 * a packet), and False if not (e.g. when receiving a packet).
613 */
614 static void usbdev_transfer(uint32_t *destination,
615 const uint32_t *source,
616 uint8_t size,
617 bool toDevice)
618 {
619 // Unroll word transfer. Each word transfer is 4 bytes, so we must round
620 // to the closest multiple of (4 * words) when unrolling.
621 constexpr uint8_t UnrollFactor = 4u;
622 constexpr uint32_t UnrollMask = (UnrollFactor * 4u) - 1;
623
624 // Round down to the previous multiple for unrolling
625 const uint32_t UnrollSize = (size & ~UnrollMask);
626 const uint32_t *sourceEnd = reinterpret_cast<uint32_t *>(
627 reinterpret_cast<uintptr_t>(source) + UnrollSize);
628
629 // This is manulally unrolled for two reasons:
630 // 1. We can't do partial writes to the USB packet buffer,
631 // which memcpy will attempt and causes a BUS fault.
632 // 2. In the sonata system at the time of writing,
633 // the core clock is 40MHz compared to the USB device's 48MHz.
634 // This approach was found to be significantly faster than when
635 // left to compiler to optimisation.
636 //
637 // Ensure the unrolling here matches `UnrollFactor`.
638 while (source < sourceEnd)
639 {
640 destination[0] = source[0];
641 destination[1] = source[1];
642 destination[2] = source[2];
643 destination[3] = source[3];
644 destination += UnrollFactor;
645 source += UnrollFactor;
646 }
647
648 // Copy the remaining whole words.
649 for (size &= UnrollMask; size >= UnrollFactor; size -= UnrollFactor)
650 {
651 *destination++ = *source++;
652 }
653 if (size == 0)
654 {
655 return;
656 }
657
658 // Copy trailing tail bytes, as USBDEV only supports 32-bit accesses.
659 if (toDevice)
660 {
661 // Collect final bytes into a word.
662 const volatile uint8_t *trailingBytes =
663 reinterpret_cast<const volatile uint8_t *>(source);
664 uint32_t partialWord = trailingBytes[0];
665 if (size > 1)
666 {
667 partialWord |= trailingBytes[1] << 8;
668 }
669 if (size > 2)
670 {
671 partialWord |= trailingBytes[2] << 16;
672 }
673 // Write the final word to the device.
674 *destination = partialWord;
675 }
676 else
677 {
678 volatile uint8_t *destinationBytes =
679 reinterpret_cast<volatile uint8_t *>(destination);
680 // Collect the final word from the device.
681 const uint32_t TrailingBytes = *source;
682 // Unpack it into final bytes.
683 destinationBytes[0] = static_cast<uint8_t>(TrailingBytes);
684 if (size > 1)
685 {
686 destinationBytes[1] = static_cast<uint8_t>(TrailingBytes >> 8);
687 }
688 if (size > 2)
689 {
690 destinationBytes[2] = static_cast<uint8_t>(TrailingBytes >> 16);
691 }
692 }
693 }
694};
A driver for OpenTitan USB Device, which is used in the Sonata system.
uint32_t outDataToggle
Registers for configuring if endpoints data toggle on transactions.
uint32_t phyConfig
Config register for the USB PHY pins.
uint32_t receiveEnableOut
Register to enable receive OUT transactions.
std::optional< ReceiveBufferInfo > packet_take() volatile
If a packet has been received, removes the packet's buffer from the receive FIFO giving it's informat...
void packet_data_get(ReceiveBufferInfo bufferInfo, uint32_t *destination) volatile
Retrieves the data from a buffer containing a received packet.
uint32_t receiveEnableSetup
Register to enable receive SETUP transactions.
UsbdevInterrupt
Interrupt definitions for OpenTitan's USB Device.
@ AvailableOutEmpty
Interrupt asserted whilst the Available OUT buffer is empty.
@ PacketReceived
Interrupt asserted whilst the receive FIFO (buffer) is not empty.
@ PacketSent
Interrupt asserted when a packet was sent as part of an IN transaction, but not cleared from the inSe...
@ ReceiveFull
Interrupt asserted whilst the Receive buffer is full.
@ LinkResume
Interrupt raised on link transition from suspended to non-idle.
@ LinkInError
Interrupt raised when an error occurs during an IN transaction.
@ Powered
Interrupt raised when VBUS (power supply) is detected.
@ FrameUpdated
Interrupt raised when the USB frame number is updated with a valid SOF (Start of Frame) packet.
@ AvailableBufferOverflow
Interrupt raised when the Available OUT buffer or the Available SETUP buffer overflows.
@ HostLost
Interrupt raised when the link is active, but a Start of Frame (SOF) packet has not been received wit...
@ LinkSuspend
Interrupt raised when the link has entered the suspend state, due to being idle for more than 3 milli...
@ LinkReset
Interrupt raised when a Bus Reset condition is indicated on the link by the link being held in an SE0...
@ BitstuffingError
Interrupt raised when a bit stuffing violation is detected.
@ PacketIdentifierError
Interrupt raised when an invalid Packet Identifier is received.
@ Disconnected
Interrupt raised when VBUS (power supply) is lost, i.e.
@ RedundancyCheckError
Interrupt raised when a CRC (cyclic redundancy check) error occurs on a received packet; i....
@ AvailableSetupEmpty
Interrupt asserted whilst the Available SETUP buffer is empty.
@ LinkOutError
Interrupt raised when an error occurs during an OUT transaction.
int connect() volatile
Connect the device to the USB, indicating its presence to the USB host controller.
int init(uint64_t &bufferBitmap) volatile
Initialise the USB device, ensuring that packet buffers are available for reception and that the PHY ...
int in_endpoint_configure(uint8_t endpointId, bool enabled, bool isochronous) volatile
Set up the configuration of an IN endpoint for the USB device.
int device_address_set(uint8_t address) volatile
Set the device address on the USB; this address will have been supplied by the USB host controller in...
bool connected() volatile
Check whether the USB device is connected (i.e.
uint32_t inSent
Register showing ACK receival to indicate a successful IN send.
uint64_t supply_buffers(uint64_t bufferBitmap) volatile
Ensure that the Available OUT and Available SETUP buffers are kept supplied with buffers for packet r...
static constexpr uint8_t MaxPacketLength
Supported sizes for the USB Device.
uint32_t outIsochronous
Registers for configuring which endpoints should be treated as isochronous endpoints.
ConfigInField
Definitions of fields (and their locations) for a Config In register (where there is one such registe...
void interrupt_disable(UsbdevInterrupt interrupt) volatile
Disable a specified interrupt / interrupts.
void packet_send(uint8_t bufferId, uint8_t endpointId, const uint32_t *data, uint8_t size) volatile
Present a packet on the specified IN endpoint for collection by the USB host controller.
uint32_t interruptState
Device Registers.
uint32_t outStall
Registers for controlling the stalling of OUT and IN endpoints.
ReceiveBufferField
Definitions of fields (and their locations) for the Receive FIFO buffer register (offset 0x28).
void disconnect() volatile
Disconnect the device from the USB.
UsbControlField
Definitions of fields (and their locations) for the USB Control register (offset 0x10).
void interrupt_enable(UsbdevInterrupt interrupt) volatile
Enable a specified interrupt / interrupts.
int endpoint_stalling_set(uint8_t endpointId, bool stalling) volatile
Set the STALL state of a specified endpoint pair (both IN and OUT).
static constexpr uint32_t BufferStartAddress
The offset from the start of the USB Device MMIO region at which packet buffer memory begins.
UsbStatusField
Definitions of fields (and their locations) for the USB Status register (offset 0x1c).
int out_endpoint_configure(uint8_t endpointId, bool enabled, bool setup, bool isochronous) volatile
Set up the configuration of an OUT endpoint for the USB device.
PhyConfigField
Definitions of fields (and their locations) for the PHY Config Register (offset 0x8c).
int retrieve_collected_packet(uint8_t &endpointId, uint8_t &bufferId) volatile
Check and retrieve the endpoint and buffer numbers of a recently-collected IN data packet.
uint32_t setNotAcknowledgeOut
Register to set NAK (Not/Negated Acknowledge) after OUT transactions.
uint32_t configIn[MaxEndpoints]
IN transaction configuration registers.
Utility class to delete copy and move contructors.
Definition utils.hh:53
The information associated with a received packet.
constexpr uint16_t size()
The size of the received packet.
constexpr uint8_t buffer_id()
The buffer ID used to store the received packet.
constexpr bool is_setup()
Whether the received packet was a setup packet.
constexpr uint8_t endpoint_id()
The endpoint ID the received packet was received on.
Miscellaneous utility functions and classes.