Software APIs
spi_host_testutils.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 "sw/device/lib/testing/spi_host_testutils.h"
6 
8 #include "sw/device/lib/testing/pinmux_testutils.h"
9 #include "sw/device/lib/testing/test_framework/check.h"
10 
11 status_t spi_host_testutils_configure_host0_pad_attrs(dif_pinmux_t *pinmux) {
12  // Set fast slew rate and strong drive strengh for SPI host0 pads.
13  dif_pinmux_pad_attr_t out_attr;
14  dif_pinmux_pad_attr_t in_attr = {
15  .slew_rate = 1,
16  .drive_strength = 3,
17  // Set weak pull-ups for all the pads.
18  .flags = kDifPinmuxPadAttrPullResistorEnable |
19  kDifPinmuxPadAttrPullResistorUp};
20  dif_result_t res;
21  for (uint32_t i = 0; i < kDtSpiHostPeriphIoCount; ++i) {
22  dt_periph_io_t periph_io =
23  dt_spi_host_periph_io(kDtSpiHost0, (dt_spi_host_periph_io_t)i);
24  dt_pad_t pad = dt_periph_io_dio_pad(periph_io);
25  res = dif_pinmux_pad_write_attrs_dt(pinmux, pad, in_attr, &out_attr);
26  if (res == kDifError) {
27  // Some target platforms may not support the specified value for slew rate
28  // and drive strength. If that's the case, use the values actually
29  // supported.
30  if (out_attr.slew_rate != in_attr.slew_rate) {
31  LOG_INFO(
32  "Specified slew rate not supported, trying supported slew rate");
33  in_attr.slew_rate = out_attr.slew_rate;
34  }
35  if (out_attr.drive_strength != in_attr.drive_strength) {
36  LOG_INFO(
37  "Specified drive strength not supported, trying supported drive "
38  "strength");
39  in_attr.drive_strength = out_attr.drive_strength;
40  }
41  CHECK_DIF_OK(
42  dif_pinmux_pad_write_attrs_dt(pinmux, pad, in_attr, &out_attr));
43  // Note: fallthrough with the modified `in_attr` so that the same
44  // attributes are used for all pads.
45  }
46  }
47  return OK_STATUS();
48 }
49 
50 // `extern` declarations to give the inline functions in the
51 // corresponding header a link location.
52 extern status_t spi_host_testutils_is_active(dif_spi_host_t *spi_host);
53 
54 status_t spi_host_testutils_flush(dif_spi_host_t *spi_host) {
56  uint8_t dummy[sizeof(uint32_t)];
57  TRY(dif_spi_host_get_status(spi_host, &status));
58  while (!status.rx_empty) {
59  TRY(dif_spi_host_fifo_read(spi_host, &dummy, sizeof(dummy)));
60  TRY(dif_spi_host_get_status(spi_host, &status));
61  }
62  return OK_STATUS();
63 }
64 
65 #if defined(OPENTITAN_IS_EARLGREY)
66 /**
67  * Define a spi pinmux configuration.
68  */
69 typedef struct spi_host1_pinmux_pads {
70  dt_pad_t clk;
71  dt_pad_t sd0;
72  dt_pad_t sd1;
73  dt_pad_t sd2;
74  dt_pad_t sd3;
75 } spi_host1_pinmux_pads_t;
76 
77 /**
78  * This table stores spi host 1 pin mappings of different platforms.
79  * This is used to connect spi host 1 to mio pins based on the platform.
80  */
81 static const spi_host1_pinmux_pads_t kSpiHost1PinmuxMap[] = {
82  [kSpiPinmuxPlatformIdCw310] =
83  {
84  .clk = kDtPadIoa3,
85  .sd0 = kDtPadIoa5,
86  .sd1 = kDtPadIoa4,
87  .sd2 = kDtPadIoa8,
88  .sd3 = kDtPadIoa7,
89  },
90  [kSpiPinmuxPlatformIdCw340] =
91  {
92  .clk = kDtPadIoa3,
93  .sd0 = kDtPadIoa5,
94  .sd1 = kDtPadIoa4,
95  .sd2 = kDtPadIoa8,
96  .sd3 = kDtPadIoa7,
97  },
98  [kSpiPinmuxPlatformIdTeacup] =
99  {
100  .clk = kDtPadIoa3,
101  .sd0 = kDtPadIoa4,
102  .sd1 = kDtPadIoa5,
103  .sd2 = kDtPadIoa8,
104  .sd3 = kDtPadIoa7,
105  },
106 };
107 
108 status_t spi_host1_pinmux_connect_to_bob(const dif_pinmux_t *pinmux,
109  dt_pad_t csb_outsel,
110  spi_pinmux_platform_id_t platform_id) {
111  TRY_CHECK(platform_id < kSpiPinmuxPlatformIdCount);
112  const spi_host1_pinmux_pads_t *platform = &kSpiHost1PinmuxMap[platform_id];
113 
114  // CSB.
115  dt_periph_io_t csb =
116  dt_spi_host_periph_io(kDtSpiHost1, kDtSpiHostPeriphIoCsb);
117  TRY(dif_pinmux_mio_select_output(pinmux, csb_outsel, csb));
118  // SCK.
119  dt_periph_io_t sck =
120  dt_spi_host_periph_io(kDtSpiHost1, kDtSpiHostPeriphIoSck);
121  TRY(dif_pinmux_mio_select_output(pinmux, platform->clk, sck));
122  // SD0.
123  dt_periph_io_t sd0 =
124  dt_spi_host_periph_io(kDtSpiHost1, kDtSpiHostPeriphIoSd0);
125  TRY(dif_pinmux_mio_select_input(pinmux, sd0, platform->sd0));
126  TRY(dif_pinmux_mio_select_output(pinmux, platform->sd0, sd0));
127  // SD1.
128  dt_periph_io_t sd1 =
129  dt_spi_host_periph_io(kDtSpiHost1, kDtSpiHostPeriphIoSd1);
130  TRY(dif_pinmux_mio_select_input(pinmux, sd1, platform->sd1));
131  TRY(dif_pinmux_mio_select_output(pinmux, platform->sd1, sd1));
132  // SD2.
133  dt_periph_io_t sd2 =
134  dt_spi_host_periph_io(kDtSpiHost1, kDtSpiHostPeriphIoSd2);
135  TRY(dif_pinmux_mio_select_input(pinmux, sd2, platform->sd2));
136  TRY(dif_pinmux_mio_select_output(pinmux, platform->sd2, sd2));
137  // SD3.
138  dt_periph_io_t sd3 =
139  dt_spi_host_periph_io(kDtSpiHost1, kDtSpiHostPeriphIoSd3);
140  TRY(dif_pinmux_mio_select_input(pinmux, sd3, platform->sd3));
141  TRY(dif_pinmux_mio_select_output(pinmux, platform->sd3, sd3));
142  return OK_STATUS();
143 }
144 #elif defined(OPENTITAN_IS_DARJEELING)
145 // Darjeeling only has a single SPI host
146 #else
147 #error "spi_host_testutils does not support this top"
148 #endif