|
19 | 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
20 | 20 | */ |
21 | 21 |
|
22 | | -/* This example shows IO interfaces for U-boot */ |
| 22 | +/* This example shows IO interfaces for U-boot using raw SPI |
| 23 | + * For Raspberry Pi 4 with Infineon SLB9672 TPM HAT |
| 24 | + * Reference: https://github.com/wolfSSL/wolfTPM/pull/451 |
| 25 | + */ |
23 | 26 |
|
24 | 27 | #include <wolftpm/tpm2.h> |
25 | 28 | #include <wolftpm/tpm2_tis.h> |
|
43 | 46 |
|
44 | 47 | #if defined(__UBOOT__) |
45 | 48 | #include <config.h> |
| 49 | + #include <spi.h> |
| 50 | + #include <asm/io.h> |
| 51 | + #include <dm/device.h> |
| 52 | + #include <dm/device-internal.h> |
| 53 | + #include <dm/uclass.h> |
| 54 | + |
| 55 | + /* SPI bus and chip select configuration for TPM |
| 56 | + * These can be overridden in user_settings.h or board config |
| 57 | + * Official Raspberry Pi tpm-slb9670 overlay uses CE1 (GPIO7) */ |
| 58 | + #ifndef TPM_SPI_BUS |
| 59 | + #define TPM_SPI_BUS 0 |
| 60 | + #endif |
| 61 | + #ifndef TPM_SPI_CS |
| 62 | + #define TPM_SPI_CS 1 /* CE1 (GPIO7) - matches Linux tpm-slb9670 overlay */ |
| 63 | + #endif |
| 64 | + #ifndef TPM_SPI_MAX_HZ |
| 65 | + #define TPM_SPI_MAX_HZ 1000000 /* 1 MHz - safe default */ |
| 66 | + #endif |
| 67 | + #define TPM_SPI_MODE SPI_MODE_0 /* Mode 0 (CPOL=0, CPHA=0) */ |
| 68 | + |
| 69 | + /* Maximum SPI frame size */ |
| 70 | + #define MAX_SPI_FRAMESIZE 64 |
| 71 | + |
| 72 | + /* Static SPI device handles */ |
| 73 | + static struct udevice *g_spi_bus = NULL; |
| 74 | + static struct spi_slave *g_spi_slave = NULL; |
| 75 | + static int g_spi_initialized = 0; |
| 76 | + |
| 77 | + /* Initialize SPI for TPM communication */ |
| 78 | + static int uboot_spi_init(void) |
| 79 | + { |
| 80 | + int ret; |
| 81 | + |
| 82 | + if (g_spi_initialized) { |
| 83 | + return 0; |
| 84 | + } |
| 85 | + |
| 86 | + #ifdef DEBUG_WOLFTPM |
| 87 | + printf("wolfTPM: Initializing SPI bus=%d, cs=%d, hz=%d\n", |
| 88 | + TPM_SPI_BUS, TPM_SPI_CS, TPM_SPI_MAX_HZ); |
| 89 | + #endif |
| 90 | + |
| 91 | + /* Get or create SPI bus and slave device */ |
| 92 | + ret = _spi_get_bus_and_cs(TPM_SPI_BUS, TPM_SPI_CS, |
| 93 | + TPM_SPI_MAX_HZ, TPM_SPI_MODE, |
| 94 | + "spi_generic_drv", "wolftpm_spi", |
| 95 | + &g_spi_bus, &g_spi_slave); |
| 96 | + if (ret != 0) { |
| 97 | + #ifdef DEBUG_WOLFTPM |
| 98 | + printf("wolfTPM: SPI init failed: %d\n", ret); |
| 99 | + #endif |
| 100 | + return ret; |
| 101 | + } |
| 102 | + |
| 103 | + g_spi_initialized = 1; |
| 104 | + |
| 105 | + #ifdef DEBUG_WOLFTPM |
| 106 | + printf("wolfTPM: SPI initialized successfully\n"); |
| 107 | + #endif |
| 108 | + |
| 109 | + return 0; |
| 110 | + } |
| 111 | + |
| 112 | + /* Raw SPI transfer for wolfTPM TIS layer |
| 113 | + * This is called by wolfTPM's TIS implementation for register read/write. |
| 114 | + * The txBuf/rxBuf contain TIS-formatted SPI data including the 4-byte header. |
| 115 | + */ |
46 | 116 | int TPM2_IoCb_Uboot_SPI(TPM2_CTX* ctx, const byte* txBuf, |
47 | 117 | byte* rxBuf, word16 xferSz, void* userCtx) |
48 | 118 | { |
49 | | - int ret = 0; |
50 | | - struct udevice *dev; |
| 119 | + int ret; |
| 120 | + #ifdef WOLFTPM_CHECK_WAIT_STATE |
| 121 | + int timeout = TPM_SPI_WAIT_RETRY; |
| 122 | + byte tmp_rx; |
| 123 | + #endif |
51 | 124 |
|
52 | | - /* Get the TPM device */ |
53 | | - if (ret == 0) { |
54 | | - ret = tcg2_platform_get_tpm2(&dev); |
55 | | - if ( ret != 0 || dev == NULL) { |
56 | | - #ifdef DEBUG_WOLFTPM |
57 | | - printf("Failed to get TPM device with error: %d\n", ret); |
58 | | - #endif |
59 | | - return TPM_RC_FAILURE; |
60 | | - } |
| 125 | + (void)ctx; |
| 126 | + (void)userCtx; |
| 127 | + |
| 128 | + /* Initialize SPI if needed */ |
| 129 | + ret = uboot_spi_init(); |
| 130 | + if (ret != 0) { |
| 131 | + return TPM_RC_FAILURE; |
| 132 | + } |
| 133 | + |
| 134 | + /* Claim the SPI bus */ |
| 135 | + ret = spi_claim_bus(g_spi_slave); |
| 136 | + if (ret != 0) { |
| 137 | + #ifdef DEBUG_WOLFTPM |
| 138 | + printf("wolfTPM: Failed to claim SPI bus: %d\n", ret); |
| 139 | + #endif |
| 140 | + return TPM_RC_FAILURE; |
| 141 | + } |
| 142 | + |
| 143 | + #ifdef WOLFTPM_CHECK_WAIT_STATE |
| 144 | + /* Send TIS header first (4 bytes) with CS held */ |
| 145 | + ret = spi_xfer(g_spi_slave, TPM_TIS_HEADER_SZ * 8, |
| 146 | + txBuf, rxBuf, SPI_XFER_BEGIN); |
| 147 | + if (ret != 0) { |
| 148 | + #ifdef DEBUG_WOLFTPM |
| 149 | + printf("wolfTPM: SPI header xfer failed: %d\n", ret); |
| 150 | + #endif |
| 151 | + goto cleanup; |
61 | 152 | } |
62 | 153 |
|
63 | | - /* Transfer the device data using tpm_xfer */ |
64 | | - if (ret == 0) { |
65 | | - ret = tpm_xfer(dev, txBuf, xferSz, rxBuf, &xferSz); |
66 | | - if (ret != 0) { |
| 154 | + /* Check for wait state - TPM holds ready bit low if busy */ |
| 155 | + if ((rxBuf[TPM_TIS_HEADER_SZ - 1] & TPM_TIS_READY_MASK) == 0) { |
| 156 | + /* Poll for ready */ |
| 157 | + do { |
| 158 | + ret = spi_xfer(g_spi_slave, 8, NULL, &tmp_rx, 0); |
| 159 | + if (ret != 0) { |
| 160 | + break; |
| 161 | + } |
| 162 | + if (tmp_rx & TPM_TIS_READY_MASK) { |
| 163 | + break; |
| 164 | + } |
| 165 | + } while (--timeout > 0); |
| 166 | + |
| 167 | + if (timeout <= 0 || ret != 0) { |
67 | 168 | #ifdef DEBUG_WOLFTPM |
68 | | - printf("tpm_xfer failed with error: %d\n", ret); |
| 169 | + printf("wolfTPM: SPI wait state timeout\n"); |
69 | 170 | #endif |
70 | | - return TPM_RC_FAILURE; |
| 171 | + /* Deassert CS */ |
| 172 | + spi_xfer(g_spi_slave, 0, NULL, NULL, SPI_XFER_END); |
| 173 | + ret = TPM_RC_FAILURE; |
| 174 | + goto cleanup; |
71 | 175 | } |
72 | 176 | } |
73 | 177 |
|
74 | | - return TPM_RC_SUCCESS; |
| 178 | + /* Transfer remainder of data with CS deasserted at end */ |
| 179 | + if (xferSz > TPM_TIS_HEADER_SZ) { |
| 180 | + ret = spi_xfer(g_spi_slave, (xferSz - TPM_TIS_HEADER_SZ) * 8, |
| 181 | + &txBuf[TPM_TIS_HEADER_SZ], |
| 182 | + &rxBuf[TPM_TIS_HEADER_SZ], |
| 183 | + SPI_XFER_END); |
| 184 | + } else { |
| 185 | + /* Just deassert CS if no more data */ |
| 186 | + ret = spi_xfer(g_spi_slave, 0, NULL, NULL, SPI_XFER_END); |
| 187 | + } |
| 188 | + |
| 189 | + #else |
| 190 | + /* No wait state handling - send entire message at once */ |
| 191 | + ret = spi_xfer(g_spi_slave, xferSz * 8, txBuf, rxBuf, |
| 192 | + SPI_XFER_BEGIN | SPI_XFER_END); |
| 193 | + #endif /* WOLFTPM_CHECK_WAIT_STATE */ |
| 194 | + |
| 195 | + if (ret != 0) { |
| 196 | + ret = TPM_RC_FAILURE; |
| 197 | + } else { |
| 198 | + ret = TPM_RC_SUCCESS; |
| 199 | + } |
| 200 | + |
| 201 | + #ifdef WOLFTPM_CHECK_WAIT_STATE |
| 202 | + cleanup: |
| 203 | + #endif |
| 204 | + spi_release_bus(g_spi_slave); |
| 205 | + |
| 206 | + return ret; |
75 | 207 | } |
| 208 | + |
76 | 209 | #endif /* __UBOOT__ */ |
77 | 210 | #endif /* WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI */ |
78 | 211 | #endif /* WOLFTPM_INCLUDE_IO_FILE */ |
|
0 commit comments