blob: af52cf530fc3bafdb669e8f80ab6a6306107a152 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// USB device test
//
// This test is a stripped down version of the hello_usbdev example application.
// It requires interaction with the USB DPI model mimicking the host and thus
// can only be run in the Verilator simulation. The test initializes the USB
// device and configures USB Endpoint 1 as a simpleserial endpoint. The test
// then starts polling the USB device for data sent by the host. Any data
// received on Endpoint 1 is stored in a buffer and printed via UART.
//
// The DPI model mimicks the USB host. After device initialization, it detects
// the assertion of the pullup and first assigns an address to the device. It
// then sends various USB transactions to the device including two OUT
// transactions with a data payload of "Hi!" to Endpoint 1. If these two OUT
// transactions are succesfully received by the device, the test passes.
#include "sw/device/lib/dif/dif_pinmux.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/pinmux_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/lib/testing/usb_testutils.h"
#include "sw/device/lib/testing/usb_testutils_controlep.h"
#include "sw/device/lib/testing/usb_testutils_simpleserial.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
/**
* Configuration values for USB.
*/
static const uint8_t config_descriptors[] = {
USB_CFG_DSCR_HEAD(
USB_CFG_DSCR_LEN + 2 * (USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN),
2),
VEND_INTERFACE_DSCR(0, 2, 0x50, 1),
USB_BULK_EP_DSCR(0, 1, 32, 0),
USB_BULK_EP_DSCR(1, 1, 32, 4),
VEND_INTERFACE_DSCR(1, 2, 0x50, 1),
USB_BULK_EP_DSCR(0, 2, 32, 0),
USB_BULK_EP_DSCR(1, 2, 32, 4),
};
/**
* Test descriptor
*/
static const uint8_t test_descriptor[] = {
USB_TESTUTILS_TEST_DSCR(0, 0, 0, 0, 0)};
/**
* USB device context types.
*/
static usb_testutils_ctx_t usbdev;
static usb_testutils_controlep_ctx_t usbdev_control;
static usb_testutils_ss_ctx_t simple_serial;
/**
* Pinmux handle
*/
static dif_pinmux_t pinmux;
/**
* Makes `c` into a printable character, replacing it with `replacement`
* as necessary.
*/
static char make_printable(char c, char replacement) {
if (c == 0xa || c == 0xd) {
return c;
}
if (c < ' ' || c > '~') {
c = replacement;
}
return c;
}
static const size_t kExpectedUsbCharsRecved = 6;
static const char kExpectedUsbRecved[7] = "Hi!Hi!";
static size_t usb_chars_recved_total;
static char buffer[7];
/**
* Callback for processing USB reciept.
*/
static void usb_receipt_callback(uint8_t c) {
c = make_printable(c, '?');
base_printf("%c", c);
if (usb_chars_recved_total < kExpectedUsbCharsRecved) {
buffer[usb_chars_recved_total] = c;
++usb_chars_recved_total;
}
}
OTTF_DEFINE_TEST_CONFIG();
bool test_main(void) {
CHECK(kDeviceType == kDeviceSimVerilator || kDeviceType == kDeviceFpgaCw310,
"This test is not expected to run on platforms other than the "
"Verilator simulation or CW310 FPGA. It needs the USB DPI model "
"or host application.");
LOG_INFO("Running USBDEV test");
CHECK_DIF_OK(dif_pinmux_init(
mmio_region_from_addr(TOP_EARLGREY_PINMUX_AON_BASE_ADDR), &pinmux));
pinmux_testutils_init(&pinmux);
CHECK_DIF_OK(dif_pinmux_input_select(
&pinmux, kTopEarlgreyPinmuxPeripheralInUsbdevSense,
kTopEarlgreyPinmuxInselIoc7));
// Call `usbdev_init` here so that DPI will not start until the
// simulation has finished all of the printing, which takes a while
// if `--trace` was passed in.
usb_testutils_init(&usbdev, /*pinflip=*/false, /*en_diff_rcvr=*/false,
/*tx_use_d_se0=*/false);
usb_testutils_controlep_init(&usbdev_control, &usbdev, 0, config_descriptors,
sizeof(config_descriptors), test_descriptor,
sizeof(test_descriptor));
while (usbdev_control.device_state != kUsbTestutilsDeviceConfigured) {
usb_testutils_poll(&usbdev);
}
usb_testutils_simpleserial_init(&simple_serial, &usbdev, 1,
usb_receipt_callback);
while (usb_chars_recved_total < kExpectedUsbCharsRecved) {
usb_testutils_poll(&usbdev);
}
base_printf("\r\n");
for (int i = 0; i < kExpectedUsbCharsRecved; i++) {
CHECK(buffer[i] == kExpectedUsbRecved[i],
"Received char #%d mismatched: exp = %x, actual = %x", i,
kExpectedUsbRecved[i], buffer[i]);
}
LOG_INFO("USB received %d characters: %s", usb_chars_recved_total, buffer);
return true;
}