coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
cr50.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 
3 #include <drivers/spi/tpm/tpm.h>
4 #include <security/tpm/tis.h>
5 #include <string.h>
6 #include <types.h>
7 
8 #define CR50_DID_VID 0x00281ae0L
9 #define TI50_DID_VID 0x504a6666L
10 
11 #define CR50_BOARD_CFG_LOCKBIT_MASK 0x80000000U
12 #define CR50_BOARD_CFG_FEATUREBITS_MASK 0x3FFFFFFFU
13 
14 #define CR50_BOARD_CFG_100US_READY_PULSE 0x00000001U
15 #define CR50_BOARD_CFG_VALUE \
16  (CONFIG(CR50_USE_LONG_INTERRUPT_PULSES) \
17  ? CR50_BOARD_CFG_100US_READY_PULSE : 0)
18 
22 };
23 
24 #define CR50_FW_VER_REG_SPI (TPM_LOCALITY_0_SPI_BASE + 0xf90)
25 #define CR50_BOARD_CFG_REG_SPI (TPM_LOCALITY_0_SPI_BASE + 0xfe0)
26 
27 #define CR50_FW_VER_REG_I2C 0x0f
28 #define CR50_BOARD_CFG_REG_I2C 0x1c
29 
30 /* Return register address, which depends on the bus type, or -1 for error. */
31 static int get_reg_addr(enum cr50_register reg)
32 {
33  if (CONFIG(SPI_TPM)) {
34  switch (reg) {
35  case CR50_FW_VER_REG:
36  return CR50_FW_VER_REG_SPI;
37  case CR50_BOARD_CFG_REG:
39  default:
40  return -1;
41  }
42  }
43 
44  if (CONFIG(I2C_TPM)) {
45  switch (reg) {
46  case CR50_FW_VER_REG:
47  return CR50_FW_VER_REG_I2C;
48  case CR50_BOARD_CFG_REG:
50  default:
51  return -1;
52  }
53  }
54 
55  return -1;
56 }
57 
59 {
60  /* Cr50 supports the CR50_BOARD_CFG register from version 0.5.5 / 0.6.5
61  * and onwards. */
62  if (version->epoch > 0 || version->major >= 7
63  || (version->major >= 5 && version->minor >= 5))
64  return true;
65 
66  printk(BIOS_INFO, "Cr50 firmware does not support CR50_BOARD_CFG, version: %d.%d.%d\n",
67  version->epoch, version->major, version->minor);
68 
69  return false;
70 }
71 
72 /*
73  * Expose method to read the CR50_BOARD_CFG register, will return zero if
74  * register not supported by Cr50 firmware.
75  */
77 {
78  struct cr50_firmware_version ver;
80 
82  return 0;
83 
84  if (!cr50_fw_supports_board_cfg(&ver))
85  return 0;
86 
88  sizeof(value));
89  if (ret != CB_SUCCESS) {
90  printk(BIOS_ERR, "Error reading from Cr50\n");
91  return 0;
92  }
93 
95 }
96 
97 /**
98  * Set the BOARD_CFG register on the TPM chip to a particular compile-time constant value.
99  */
100 enum cb_err cr50_set_board_cfg(void)
101 {
102  /* If we get here and we aren't cr50, then we must be ti50 which does
103  * not currently need to support a board_cfg register. */
104  if (!CONFIG(TPM_GOOGLE_CR50))
105  return CB_SUCCESS;
106 
107  struct cr50_firmware_version ver;
108  enum cb_err ret;
109  uint32_t value;
110 
112  return CB_ERR;
113 
114  if (!cr50_fw_supports_board_cfg(&ver))
115  return CB_ERR;
116 
117  /* Set the CR50_BOARD_CFG register, for e.g. asking cr50 to use longer ready pulses. */
119  if (ret != CB_SUCCESS) {
120  printk(BIOS_ERR, "Error reading from Cr50\n");
121  return CB_ERR;
122  }
123 
125  printk(BIOS_INFO, "Current CR50_BOARD_CFG = 0x%08x, matches desired = 0x%08x\n",
127  return CB_SUCCESS;
128  }
129 
131  /* The high bit is set, meaning that the Cr50 is already locked on a particular
132  * value for the register, but not the one we wanted. */
133  printk(BIOS_ERR, "Current CR50_BOARD_CFG = 0x%08x, does not match"
134  "desired = 0x%08x\n", value, CR50_BOARD_CFG_VALUE);
135  return CB_ERR;
136  }
137 
138  printk(BIOS_INFO, "Current CR50_BOARD_CFG = 0x%08x, setting to 0x%08x\n",
141 
143  if (ret != CB_SUCCESS) {
144  printk(BIOS_ERR, "Error writing to cr50\n");
145  return ret;
146  }
147 
148  return CB_SUCCESS;
149 }
150 
152 {
153  if (CONFIG(TPM_GOOGLE_CR50))
155 
156  /* Ti50 and future GSCs will support only long interrupt pulses. */
157  return true;
158 }
159 
160 static enum cb_err cr50_parse_fw_version(const char *version_str,
161  struct cr50_firmware_version *ver)
162 {
163  int epoch, major, minor;
164 
165  char *number = strstr(version_str, " RW_A:");
166  if (!number)
167  number = strstr(version_str, " RW_B:");
168  if (!number)
169  return CB_ERR_ARG;
170  number += 6; /* Skip past the colon. */
171 
172  epoch = skip_atoi(&number);
173  if (*number++ != '.')
174  return CB_ERR_ARG;
175  major = skip_atoi(&number);
176  if (*number++ != '.')
177  return CB_ERR_ARG;
178  minor = skip_atoi(&number);
179 
180  ver->epoch = epoch;
181  ver->major = major;
182  ver->minor = minor;
183  return CB_SUCCESS;
184 }
185 
187 {
189 
192  goto success;
193 
194  int chunk_count = 0;
195  size_t chunk_size = 50;
196  char version_str[301];
198 
199  /*
200  * Does not really matter what's written, this just makes sure
201  * the version is reported from the beginning.
202  */
203  tis_vendor_write(addr, &chunk_size, 1);
204 
205  /*
206  * Read chunk_size bytes at a time, last chunk will be zero padded.
207  */
208  do {
209  uint8_t *buf = (uint8_t *)version_str + chunk_count * chunk_size;
210  tis_vendor_read(addr, buf, chunk_size);
211  if (!version_str[++chunk_count * chunk_size - 1])
212  /* Zero padding detected: end of string. */
213  break;
214  /* Check if there is enough room for reading one more chunk. */
215  } while (chunk_count * chunk_size < sizeof(version_str) - chunk_size);
216 
217  version_str[chunk_count * chunk_size] = '\0';
218  printk(BIOS_INFO, "Firmware version: %s\n", version_str);
219 
221  printk(BIOS_ERR, "Did not recognize Cr50 version format\n");
222  return CB_ERR;
223  }
224 
225 success:
226  if (version)
228  return CB_SUCCESS;
229 }
pte_t value
Definition: mmu.c:91
cb_err
coreboot error codes
Definition: cb_err.h:15
@ CB_ERR
Generic error code.
Definition: cb_err.h:17
@ CB_ERR_ARG
Invalid argument.
Definition: cb_err.h:18
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
static u32 addr
Definition: cirrus.c:14
#define printk(level,...)
Definition: stdlib.h:16
enum cb_err tis_vendor_read(unsigned int addr, void *buffer, size_t bytes)
Definition: cr50.c:522
enum cb_err tis_vendor_write(unsigned int addr, const void *buffer, size_t bytes)
Definition: cr50.c:517
#define CR50_BOARD_CFG_LOCKBIT_MASK
Definition: cr50.c:11
static uint32_t cr50_get_board_cfg(void)
Definition: cr50.c:76
cr50_register
Definition: cr50.c:19
@ CR50_BOARD_CFG_REG
Definition: cr50.c:21
@ CR50_FW_VER_REG
Definition: cr50.c:20
enum cb_err cr50_get_firmware_version(struct cr50_firmware_version *version)
Definition: cr50.c:186
static bool cr50_fw_supports_board_cfg(struct cr50_firmware_version *version)
Definition: cr50.c:58
#define CR50_FW_VER_REG_I2C
Definition: cr50.c:27
#define CR50_BOARD_CFG_100US_READY_PULSE
Definition: cr50.c:14
static enum cb_err cr50_parse_fw_version(const char *version_str, struct cr50_firmware_version *ver)
Definition: cr50.c:160
static int get_reg_addr(enum cr50_register reg)
Definition: cr50.c:31
#define CR50_BOARD_CFG_REG_I2C
Definition: cr50.c:28
#define CR50_BOARD_CFG_VALUE
Definition: cr50.c:15
enum cb_err cr50_set_board_cfg(void)
Set the BOARD_CFG register on the TPM chip to a particular compile-time constant value.
Definition: cr50.c:100
#define CR50_FW_VER_REG_SPI
Definition: cr50.c:24
#define CR50_BOARD_CFG_REG_SPI
Definition: cr50.c:25
bool cr50_is_long_interrupt_pulse_enabled(void)
Definition: cr50.c:151
#define CR50_BOARD_CFG_FEATUREBITS_MASK
Definition: cr50.c:12
@ CONFIG
Definition: dsi_common.h:201
unsigned int version[2]
Definition: edid.c:55
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static uint8_t * buf
Definition: uart.c:7
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
unsigned int skip_atoi(char **s)
Definition: string.c:126
char * strstr(const char *haystack, const char *needle)
Definition: string.c:165
static int number(void(*tx_byte)(unsigned char byte, void *data), unsigned long long inum, int base, int size, int precision, int type, void *data)
Definition: vtxprintf.c:22