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
11status_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 =
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) {
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) {
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.
52extern status_t spi_host_testutils_is_active(dif_spi_host_t *spi_host);
53
54status_t spi_host_testutils_flush(dif_spi_host_t *spi_host) {
55 dif_spi_host_status_t status;
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 */
69typedef 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 */
81static 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
108status_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