Software APIs
hello_usbdev.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include <stdalign.h>
6 #include <stdbool.h>
7 
8 #include "sw/device/examples/demos.h"
16 #include "sw/device/lib/testing/pinmux_testutils.h"
17 #include "sw/device/lib/testing/test_framework/check.h"
18 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
19 #include "sw/device/lib/testing/usb_testutils.h"
20 #include "sw/device/lib/testing/usb_testutils_controlep.h"
21 #include "sw/device/lib/testing/usb_testutils_simpleserial.h"
22 
23 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
24 
25 // These just for the '/' printout
26 #define USBDEV_BASE_ADDR TOP_EARLGREY_USBDEV_BASE_ADDR
27 #include "usbdev_regs.h" // Generated.
28 
29 #define REG32(add) *((volatile uint32_t *)(add))
30 
31 OTTF_DEFINE_TEST_CONFIG();
32 
33 /**
34  * Configuration values for USB.
35  */
36 static uint8_t config_descriptors[] = {
37  USB_CFG_DSCR_HEAD(
38  USB_CFG_DSCR_LEN + 2 * (USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN),
39  2),
40  VEND_INTERFACE_DSCR(0, 2, 0x50, 1),
41  USB_BULK_EP_DSCR(0, 1, 32, 0),
42  USB_BULK_EP_DSCR(1, 1, 32, 4),
43  VEND_INTERFACE_DSCR(1, 2, 0x50, 1),
44  USB_BULK_EP_DSCR(0, 2, 32, 0),
45  USB_BULK_EP_DSCR(1, 2, 32, 4),
46 };
47 
48 /**
49  * USB device context types.
50  */
51 static usb_testutils_ctx_t usbdev;
52 static usb_testutils_controlep_ctx_t usbdev_control;
53 static usb_testutils_ss_ctx_t simple_serial0;
54 static usb_testutils_ss_ctx_t simple_serial1;
55 
56 /**
57  * Makes `c` into a printable character, replacing it with `replacement`
58  * as necessary.
59  */
60 static char make_printable(char c, char replacement) {
61  if (c == 0xa || c == 0xd) {
62  return c;
63  }
64 
65  if (c < ' ' || c > '~') {
66  c = replacement;
67  }
68  return c;
69 }
70 
71 static const size_t kExpectedUsbCharsRecved = 6;
72 static size_t usb_chars_recved_total;
73 
74 static dif_gpio_t gpio;
75 static dif_pinmux_t pinmux;
76 static dif_uart_t uart;
77 
78 /**
79  * Callbacks for processing USB reciept. The latter increments the
80  * recieved character by one, to make them distinct.
81  */
82 static void usb_receipt_callback_0(uint8_t c) {
83  c = make_printable(c, '?');
84  CHECK_DIF_OK(dif_uart_byte_send_polled(&uart, c));
85  ++usb_chars_recved_total;
86 }
87 static void usb_receipt_callback_1(uint8_t c) {
88  c = make_printable(c + 1, '?');
89  CHECK_DIF_OK(dif_uart_byte_send_polled(&uart, c));
90  ++usb_chars_recved_total;
91 }
92 
93 /**
94  * USB Send String
95  *
96  * Send a 0 terminated string to the USB one byte at a time.
97  * The send byte code will flush the endpoint if needed.
98  *
99  * @param string Zero terminated string to send.
100  * @param ss_ctx Pointer to simple string endpoint context to send through.
101  */
102 static void usb_send_str(const char *string, usb_testutils_ss_ctx_t *ss_ctx) {
103  for (int i = 0; string[i] != 0; ++i) {
104  CHECK_STATUS_OK(usb_testutils_simpleserial_send_byte(ss_ctx, string[i]));
105  }
106 }
107 
108 // These GPIO bits control USB PHY configuration
109 static const uint32_t kPinflipMask = (1 << 8);
110 static const uint32_t kDiffXcvrMask = (1 << 9);
111 static const uint32_t kUPhyMask = (1 << 10);
112 
113 static dif_pinmux_index_t leds[] = {
118 };
119 
120 static dif_pinmux_index_t switches[] = {
125 };
126 
127 void configure_pinmux(void) {
128  pinmux_testutils_init(&pinmux);
129  // Hook up some LEDs.
130  for (size_t i = 0; i < ARRAYSIZE(leds); ++i) {
132  CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, leds[i], gpio));
133  }
134  // Hook up DIP switches.
135  for (size_t i = 0; i < ARRAYSIZE(switches); ++i) {
137  CHECK_DIF_OK(dif_pinmux_input_select(&pinmux, gpio, switches[i]));
138  }
139 }
140 
141 void _ottf_main(void) {
142  CHECK_DIF_OK(dif_pinmux_init(
144  configure_pinmux();
145 
146  CHECK_DIF_OK(dif_uart_init(
148  CHECK(kUartBaudrate <= UINT32_MAX, "kUartBaudrate must fit in uint32_t");
149  CHECK(kClockFreqPeripheralHz <= UINT32_MAX,
150  "kClockFreqPeripheralHz must fit in uint32_t");
151  CHECK_DIF_OK(dif_uart_configure(
152  &uart, (dif_uart_config_t){
153  .baudrate = (uint32_t)kUartBaudrate,
154  .clk_freq_hz = (uint32_t)kClockFreqPeripheralHz,
155  .parity_enable = kDifToggleDisabled,
156  .parity = kDifUartParityEven,
157  .tx_enable = kDifToggleEnabled,
158  .rx_enable = kDifToggleEnabled,
159  }));
160  base_uart_stdout(&uart);
161 
162  CHECK_DIF_OK(
163  dif_gpio_init(mmio_region_from_addr(TOP_EARLGREY_GPIO_BASE_ADDR), &gpio));
164  // Enable GPIO: 0-7 and 16 is input; 8-15 is output.
165  CHECK_DIF_OK(dif_gpio_output_set_enabled_all(&gpio, 0x000ff));
166 
167  LOG_INFO("Hello, USB!");
168  LOG_INFO("Built at: " __DATE__ ", " __TIME__);
169 
170  demo_gpio_startup(&gpio);
171 
172  // Call `usbdev_init` here so that DPI will not start until the
173  // simulation has finished all of the printing, which takes a while
174  // if `--trace` was passed in.
175  uint32_t gpio_state;
176  CHECK_DIF_OK(dif_gpio_read_all(&gpio, &gpio_state));
177  bool pinflip = gpio_state & kPinflipMask ? true : false;
178  bool differential_xcvr = gpio_state & kDiffXcvrMask ? true : false;
179  bool uphy = gpio_state & kUPhyMask ? true : false;
180  LOG_INFO("PHY settings: pinflip=%d differential_xcvr=%d USB Phy=%d", pinflip,
181  differential_xcvr, uphy);
182  // Connect correct VBUS detection pin
183  if (uphy) {
184  CHECK_DIF_OK(dif_pinmux_input_select(
187  } else {
188  CHECK_DIF_OK(dif_pinmux_input_select(
191  }
192 
193  // The TI phy always uses a differential TX interface
194  CHECK_STATUS_OK(usb_testutils_init(&usbdev, pinflip, differential_xcvr,
195  differential_xcvr && !uphy));
196 
197  CHECK_STATUS_OK(usb_testutils_controlep_init(
198  &usbdev_control, &usbdev, 0, config_descriptors,
199  sizeof(config_descriptors), NULL, 0));
200 
201  while (usbdev_control.device_state != kUsbTestutilsDeviceConfigured) {
202  CHECK_STATUS_OK(usb_testutils_poll(&usbdev));
203  }
204 
205  CHECK_STATUS_OK(usb_testutils_simpleserial_init(&simple_serial0, &usbdev, 1,
206  usb_receipt_callback_0));
207  CHECK_STATUS_OK(usb_testutils_simpleserial_init(&simple_serial1, &usbdev, 2,
208  usb_receipt_callback_1));
209 
210  bool say_hello = true;
211  bool pass_signaled = false;
212  while (true) {
213  CHECK_STATUS_OK(usb_testutils_poll(&usbdev));
214 
215  gpio_state = demo_gpio_to_log_echo(&gpio, gpio_state);
216 
217  while (true) {
218  size_t chars_available;
219  if (dif_uart_rx_bytes_available(&uart, &chars_available) != kDifOk ||
220  chars_available == 0) {
221  break;
222  }
223 
224  uint8_t rcv_char;
225  CHECK_DIF_OK(dif_uart_bytes_receive(&uart, 1, &rcv_char, NULL));
226  CHECK_DIF_OK(dif_uart_byte_send_polled(&uart, rcv_char));
227 
228  CHECK_DIF_OK(dif_gpio_write_all(&gpio, (uint32_t)rcv_char << 8));
229 
230  if (rcv_char == '/') {
231  uint32_t usb_irq_state =
232  REG32(USBDEV_BASE_ADDR + USBDEV_INTR_STATE_REG_OFFSET);
233  uint32_t usb_stat = REG32(USBDEV_BASE_ADDR + USBDEV_USBSTAT_REG_OFFSET);
234  LOG_INFO("I%04x-%08x", usb_irq_state, usb_stat);
235  } else {
236  CHECK_STATUS_OK(
237  usb_testutils_simpleserial_send_byte(&simple_serial0, rcv_char));
238  CHECK_STATUS_OK(usb_testutils_simpleserial_send_byte(&simple_serial1,
239  rcv_char + 1));
240  }
241  }
242  if (say_hello && usb_chars_recved_total > 2) {
243  usb_send_str("Hello USB World!!!!", &simple_serial0);
244  say_hello = false;
245  }
246  // Signal that the simulation succeeded.
247  if (usb_chars_recved_total >= kExpectedUsbCharsRecved && !pass_signaled) {
248  LOG_INFO("PASS!");
249  pass_signaled = true;
250  }
251  }
252 
253  LOG_INFO("USB recieved %d characters.", usb_chars_recved_total);
254 }