Software APIs
usbdev_mem_test.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 // USB packet memory test
6 //
7 // This test performs a simple read/write test of the entire USB packet memory
8 // from the CPU to check connectivity, addressing, integrity etc. A LFSR-
9 // generated byte stream is used as the test pattern.
10 //
11 // Two methods of access are tested in turn:
12 // (i) direct access using the mmio_ routines
13 // (ii) DIF-based buffer reading/writing
14 
19 #include "sw/device/lib/testing/pinmux_testutils.h"
20 #include "sw/device/lib/testing/test_framework/check.h"
22 
23 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
24 #include "sw/device/lib/dif/autogen/dif_usbdev_autogen.h"
25 
26 #define USBDEV_BASE_ADDR TOP_EARLGREY_USBDEV_BASE_ADDR
27 
28 #ifndef USBDEV_BUFFER_REG_OFFSET
29 #define USBDEV_BUFFER_REG_OFFSET 0x800u
30 #endif
31 
32 // Simple LFSR for 8-bit sequences
33 /// Note: zero is an isolated state that shall be avoided
34 #define LFSR_ADVANCE(lfsr) \
35  (uint8_t)( \
36  (uint8_t)((lfsr) << 1) ^ \
37  ((((lfsr) >> 1) ^ ((lfsr) >> 2) ^ ((lfsr) >> 3) ^ ((lfsr) >> 7)) & 1U))
38 
39 // Total size of packet buffer memory in bytes
40 #define USBDEV_PACKET_MEM_SIZE (USBDEV_NUM_BUFFERS * USBDEV_MAX_PACKET_SIZE)
41 
42 // Basic test of packet memory function from the CPU side
43 static alignas(uint32_t) uint8_t testpatt[USBDEV_PACKET_MEM_SIZE];
44 static alignas(uint32_t) uint8_t testcopy[USBDEV_PACKET_MEM_SIZE];
45 
46 static dif_usbdev_t usbdev;
47 
48 OTTF_DEFINE_TEST_CONFIG();
49 
50 /* The obvious advantage of using the DIF interface is that we are testing that
51  code too, but the disadvantage is that we have to resort to modifying the
52  buffer descriptors to perform reads because the buffers are not being used
53  in accordance with the expected flow model.
54 */
55 
56 static status_t mem_dif_write(const dif_usbdev_t *dev, const uint8_t *data,
57  size_t n) {
58  const unsigned nbufs =
59  (n + USBDEV_MAX_PACKET_SIZE - 1) / USBDEV_MAX_PACKET_SIZE;
60  TRY_CHECK(nbufs <= USBDEV_NUM_BUFFERS);
61 
62  for (unsigned id = 0u; id < nbufs; id++) {
63  TRY(dif_usbdev_buffer_raw_write(dev, (uint8_t)id,
64  &data[id * USBDEV_MAX_PACKET_SIZE],
65  USBDEV_MAX_PACKET_SIZE));
66  }
67 
68  return OK_STATUS();
69 }
70 
71 static status_t mem_dif_read(const dif_usbdev_t *dev, uint8_t *data, size_t n) {
72  const unsigned nbufs =
73  (n + USBDEV_MAX_PACKET_SIZE - 1) / USBDEV_MAX_PACKET_SIZE;
74  TRY_CHECK(nbufs <= USBDEV_NUM_BUFFERS);
75 
76  for (unsigned id = 0u; id < nbufs; id++) {
77  TRY(dif_usbdev_buffer_raw_read(dev, (uint8_t)id,
78  &data[id * USBDEV_MAX_PACKET_SIZE],
79  USBDEV_MAX_PACKET_SIZE));
80  }
81 
82  return OK_STATUS();
83 }
84 
85 // Perform a read from the usbdev packet memory, optionally using the DIF
86 // interface
87 static status_t mem_read(const dif_usbdev_t *dev, unsigned use_dif,
88  uint8_t *data, size_t n) {
89  if (use_dif) {
90  return mem_dif_read(dev, data, n);
91  } else {
92  mmio_region_memcpy_from_mmio32(dev->base_addr, USBDEV_BUFFER_REG_OFFSET,
93  data, n);
94  return OK_STATUS();
95  }
96 }
97 
98 // Write a block of data to the usbdev packet memory, optionally using the DIF
99 // interface
100 static status_t mem_write(const dif_usbdev_t *dev, unsigned use_dif,
101  const uint8_t *data, size_t n) {
102  if (use_dif) {
103  return mem_dif_write(dev, data, n);
104  } else {
105  mmio_region_memcpy_to_mmio32(dev->base_addr, USBDEV_BUFFER_REG_OFFSET, data,
106  n);
107  return OK_STATUS();
108  }
109 }
110 
111 bool test_main(void) {
112  LOG_INFO("Running USBDEV Mem Test");
113 
114  // Initialize DIF-based access to the packet buffer memory
115  CHECK_DIF_OK(
116  dif_usbdev_init(mmio_region_from_addr(USBDEV_BASE_ADDR), &usbdev));
117 
118  // Exercise mmio_ routines and then dif_usbdev_ routines in turn; it provides
119  // a bit more testing of the packet memory because the two routines exhibit
120  // different access patterns/timing.
121  for (unsigned use_dif = 0u; use_dif <= 1u; use_dif++) {
122  // Set up test pattern
123  uint8_t lfsr = 0x13u;
124  for (unsigned idx = 0u; idx < sizeof(testpatt); idx++) {
125  testpatt[idx] = lfsr;
126  lfsr = LFSR_ADVANCE(lfsr);
127  }
128 
129  // Write the generated test pattern to the usbdev packet memory
130  CHECK_STATUS_OK(mem_write(&usbdev, use_dif, testpatt, sizeof(testpatt)));
131 
132  // Invalidate the contents of the copy buffer
133  memset(testcopy, 0xffu, sizeof(testcopy));
134 
135  // Read back a copy of the test pattern from the usbdev packet memory
136  CHECK_STATUS_OK(
137  mem_read(&usbdev, use_dif, testcopy, USBDEV_PACKET_MEM_SIZE));
138 
139  // Check the copy against the original
140  CHECK_ARRAYS_EQ(testcopy, testpatt, sizeof(testcopy));
141 
142  for (unsigned idx = 0u; idx < sizeof(testpatt); idx++) {
143  // Invert the test pattern to ensure every byte is modified
144  testcopy[idx] = ~testcopy[idx];
145  }
146 
147  // Write the modified test pattern to the device memory
148  CHECK_STATUS_OK(mem_write(&usbdev, use_dif, testcopy, sizeof(testcopy)));
149 
150  // Invalidate the original test pattern buffer
151  memset(testpatt, 0xffu, sizeof(testpatt));
152 
153  // Read back the modified test pattern from the device memory
154  CHECK_STATUS_OK(mem_read(&usbdev, use_dif, testpatt, sizeof(testpatt)));
155 
156  // Check against the modified test pattern
157  CHECK_ARRAYS_EQ(testpatt, testcopy, USBDEV_PACKET_MEM_SIZE);
158  }
159 
160  return true;
161 }