Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tpm/st33zp24/spi: Add st33zp24 spi phy

st33zp24 TIS 1.2 support also SPI. It is using a proprietary protocol to
transport TIS data.

Acked-by: Jarkko Sakkinen <jarkko.sakknen@linux.intel.com>
Reviewed-by: Jason Gunthorpe <jason.gunthorpe@obsidianresearch.com>
Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com>
Signed-off-by: Peter Huewe <peterhuewe@gmx.de>

authored by

Christophe Ricard and committed by
Peter Huewe
f042a315 bf38b871

+408 -2
+10
drivers/char/tpm/st33zp24/Kconfig
··· 18 18 ST33ZP24 with i2c interface. 19 19 To compile this driver as a module, choose M here; the module will be 20 20 called tpm_st33zp24_i2c. 21 + 22 + config TCG_TIS_ST33ZP24_SPI 23 + tristate "TPM 1.2 ST33ZP24 SPI support" 24 + depends on TCG_TIS_ST33ZP24 25 + depends on SPI 26 + ---help--- 27 + This module adds support for the STMicroelectronics TPM security chip 28 + ST33ZP24 with spi interface. 29 + To compile this driver as a module, choose M here; the module will be 30 + called tpm_st33zp24_spi.
+3
drivers/char/tpm/st33zp24/Makefile
··· 7 7 8 8 tpm_st33zp24_i2c-objs = i2c.o 9 9 obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o 10 + 11 + tpm_st33zp24_spi-objs = spi.o 12 + obj-$(CONFIG_TCG_TIS_ST33ZP24_SPI) += tpm_st33zp24_spi.o
-2
drivers/char/tpm/st33zp24/i2c.c
··· 27 27 #include "st33zp24.h" 28 28 29 29 #define TPM_DUMMY_BYTE 0xAA 30 - #define TPM_WRITE_DIRECTION 0x80 31 - #define TPM_BUFSIZE 2048 32 30 33 31 struct st33zp24_i2c_phy { 34 32 struct i2c_client *client;
+392
drivers/char/tpm/st33zp24/spi.c
··· 1 + /* 2 + * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24 3 + * Copyright (C) 2009 - 2015 STMicroelectronics 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 17 + */ 18 + 19 + #include <linux/module.h> 20 + #include <linux/spi/spi.h> 21 + #include <linux/gpio.h> 22 + #include <linux/of_irq.h> 23 + #include <linux/of_gpio.h> 24 + #include <linux/tpm.h> 25 + #include <linux/platform_data/st33zp24.h> 26 + 27 + #include "st33zp24.h" 28 + 29 + #define TPM_DATA_FIFO 0x24 30 + #define TPM_INTF_CAPABILITY 0x14 31 + 32 + #define TPM_DUMMY_BYTE 0x00 33 + 34 + #define MAX_SPI_LATENCY 15 35 + #define LOCALITY0 0 36 + 37 + #define ST33ZP24_OK 0x5A 38 + #define ST33ZP24_UNDEFINED_ERR 0x80 39 + #define ST33ZP24_BADLOCALITY 0x81 40 + #define ST33ZP24_TISREGISTER_UKNOWN 0x82 41 + #define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x83 42 + #define ST33ZP24_HASH_END_BEFORE_HASH_START 0x84 43 + #define ST33ZP24_BAD_COMMAND_ORDER 0x85 44 + #define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x86 45 + #define ST33ZP24_TPM_FIFO_OVERFLOW 0x89 46 + #define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A 47 + #define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B 48 + #define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x90 49 + #define ST33ZP24_DUMMY_BYTES 0x00 50 + 51 + /* 52 + * TPM command can be up to 2048 byte, A TPM response can be up to 53 + * 1024 byte. 54 + * Between command and response, there are latency byte (up to 15 55 + * usually on st33zp24 2 are enough). 56 + * 57 + * Overall when sending a command and expecting an answer we need if 58 + * worst case: 59 + * 2048 (for the TPM command) + 1024 (for the TPM answer). We need 60 + * some latency byte before the answer is available (max 15). 61 + * We have 2048 + 1024 + 15. 62 + */ 63 + #define ST33ZP24_SPI_BUFFER_SIZE (TPM_BUFSIZE + (TPM_BUFSIZE / 2) +\ 64 + MAX_SPI_LATENCY) 65 + 66 + 67 + struct st33zp24_spi_phy { 68 + struct spi_device *spi_device; 69 + struct spi_transfer spi_xfer; 70 + u8 tx_buf[ST33ZP24_SPI_BUFFER_SIZE]; 71 + u8 rx_buf[ST33ZP24_SPI_BUFFER_SIZE]; 72 + 73 + int io_lpcpd; 74 + int latency; 75 + }; 76 + 77 + static int st33zp24_status_to_errno(u8 code) 78 + { 79 + switch (code) { 80 + case ST33ZP24_OK: 81 + return 0; 82 + case ST33ZP24_UNDEFINED_ERR: 83 + case ST33ZP24_BADLOCALITY: 84 + case ST33ZP24_TISREGISTER_UKNOWN: 85 + case ST33ZP24_LOCALITY_NOT_ACTIVATED: 86 + case ST33ZP24_HASH_END_BEFORE_HASH_START: 87 + case ST33ZP24_BAD_COMMAND_ORDER: 88 + case ST33ZP24_UNEXPECTED_READ_FIFO: 89 + case ST33ZP24_UNEXPECTED_WRITE_FIFO: 90 + case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END: 91 + return -EPROTO; 92 + case ST33ZP24_INCORECT_RECEIVED_LENGTH: 93 + case ST33ZP24_TPM_FIFO_OVERFLOW: 94 + return -EMSGSIZE; 95 + case ST33ZP24_DUMMY_BYTES: 96 + return -ENOSYS; 97 + } 98 + return code; 99 + } 100 + 101 + /* 102 + * st33zp24_spi_send 103 + * Send byte to the TIS register according to the ST33ZP24 SPI protocol. 104 + * @param: phy_id, the phy description 105 + * @param: tpm_register, the tpm tis register where the data should be written 106 + * @param: tpm_data, the tpm_data to write inside the tpm_register 107 + * @param: tpm_size, The length of the data 108 + * @return: should be zero if success else a negative error code. 109 + */ 110 + static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data, 111 + int tpm_size) 112 + { 113 + u8 data = 0; 114 + int total_length = 0, nbr_dummy_bytes = 0, ret = 0; 115 + struct st33zp24_spi_phy *phy = phy_id; 116 + struct spi_device *dev = phy->spi_device; 117 + u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf; 118 + u8 *rx_buf = phy->spi_xfer.rx_buf; 119 + 120 + /* Pre-Header */ 121 + data = TPM_WRITE_DIRECTION | LOCALITY0; 122 + memcpy(tx_buf + total_length, &data, sizeof(data)); 123 + total_length++; 124 + data = tpm_register; 125 + memcpy(tx_buf + total_length, &data, sizeof(data)); 126 + total_length++; 127 + 128 + if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) { 129 + tx_buf[total_length++] = tpm_size >> 8; 130 + tx_buf[total_length++] = tpm_size; 131 + } 132 + 133 + memcpy(&tx_buf[total_length], tpm_data, tpm_size); 134 + total_length += tpm_size; 135 + 136 + nbr_dummy_bytes = phy->latency; 137 + memset(&tx_buf[total_length], TPM_DUMMY_BYTE, nbr_dummy_bytes); 138 + 139 + phy->spi_xfer.len = total_length + nbr_dummy_bytes; 140 + 141 + ret = spi_sync_transfer(dev, &phy->spi_xfer, 1); 142 + if (ret == 0) 143 + ret = rx_buf[total_length + nbr_dummy_bytes - 1]; 144 + 145 + return st33zp24_status_to_errno(ret); 146 + } /* st33zp24_spi_send() */ 147 + 148 + /* 149 + * read8_recv 150 + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. 151 + * @param: phy_id, the phy description 152 + * @param: tpm_register, the tpm tis register where the data should be read 153 + * @param: tpm_data, the TPM response 154 + * @param: tpm_size, tpm TPM response size to read. 155 + * @return: should be zero if success else a negative error code. 156 + */ 157 + static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size) 158 + { 159 + u8 data = 0; 160 + int total_length = 0, nbr_dummy_bytes, ret; 161 + struct st33zp24_spi_phy *phy = phy_id; 162 + struct spi_device *dev = phy->spi_device; 163 + u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf; 164 + u8 *rx_buf = phy->spi_xfer.rx_buf; 165 + 166 + /* Pre-Header */ 167 + data = LOCALITY0; 168 + memcpy(tx_buf + total_length, &data, sizeof(data)); 169 + total_length++; 170 + data = tpm_register; 171 + memcpy(tx_buf + total_length, &data, sizeof(data)); 172 + total_length++; 173 + 174 + nbr_dummy_bytes = phy->latency; 175 + memset(&tx_buf[total_length], TPM_DUMMY_BYTE, 176 + nbr_dummy_bytes + tpm_size); 177 + 178 + phy->spi_xfer.len = total_length + nbr_dummy_bytes + tpm_size; 179 + 180 + /* header + status byte + size of the data + status byte */ 181 + ret = spi_sync_transfer(dev, &phy->spi_xfer, 1); 182 + if (tpm_size > 0 && ret == 0) { 183 + ret = rx_buf[total_length + nbr_dummy_bytes - 1]; 184 + 185 + memcpy(tpm_data, rx_buf + total_length + nbr_dummy_bytes, 186 + tpm_size); 187 + } 188 + 189 + return ret; 190 + } /* read8_reg() */ 191 + 192 + /* 193 + * st33zp24_spi_recv 194 + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol. 195 + * @param: phy_id, the phy description 196 + * @param: tpm_register, the tpm tis register where the data should be read 197 + * @param: tpm_data, the TPM response 198 + * @param: tpm_size, tpm TPM response size to read. 199 + * @return: number of byte read successfully: should be one if success. 200 + */ 201 + static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data, 202 + int tpm_size) 203 + { 204 + int ret; 205 + 206 + ret = read8_reg(phy_id, tpm_register, tpm_data, tpm_size); 207 + if (!st33zp24_status_to_errno(ret)) 208 + return tpm_size; 209 + return ret; 210 + } /* st33zp24_spi_recv() */ 211 + 212 + static int evaluate_latency(void *phy_id) 213 + { 214 + struct st33zp24_spi_phy *phy = phy_id; 215 + int latency = 1, status = 0; 216 + u8 data = 0; 217 + 218 + while (!status && latency < MAX_SPI_LATENCY) { 219 + phy->latency = latency; 220 + status = read8_reg(phy_id, TPM_INTF_CAPABILITY, &data, 1); 221 + latency++; 222 + } 223 + return latency - 1; 224 + } /* evaluate_latency() */ 225 + 226 + static const struct st33zp24_phy_ops spi_phy_ops = { 227 + .send = st33zp24_spi_send, 228 + .recv = st33zp24_spi_recv, 229 + }; 230 + 231 + #ifdef CONFIG_OF 232 + static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy) 233 + { 234 + struct device_node *pp; 235 + struct spi_device *dev = phy->spi_device; 236 + int gpio; 237 + int ret; 238 + 239 + pp = dev->dev.of_node; 240 + if (!pp) { 241 + dev_err(&dev->dev, "No platform data\n"); 242 + return -ENODEV; 243 + } 244 + 245 + /* Get GPIO from device tree */ 246 + gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); 247 + if (gpio < 0) { 248 + dev_err(&dev->dev, 249 + "Failed to retrieve lpcpd-gpios from dts.\n"); 250 + phy->io_lpcpd = -1; 251 + /* 252 + * lpcpd pin is not specified. This is not an issue as 253 + * power management can be also managed by TPM specific 254 + * commands. So leave with a success status code. 255 + */ 256 + return 0; 257 + } 258 + /* GPIO request and configuration */ 259 + ret = devm_gpio_request_one(&dev->dev, gpio, 260 + GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); 261 + if (ret) { 262 + dev_err(&dev->dev, "Failed to request lpcpd pin\n"); 263 + return -ENODEV; 264 + } 265 + phy->io_lpcpd = gpio; 266 + 267 + return 0; 268 + } 269 + #else 270 + static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy) 271 + { 272 + return -ENODEV; 273 + } 274 + #endif 275 + 276 + static int tpm_stm_spi_request_resources(struct spi_device *dev, 277 + struct st33zp24_spi_phy *phy) 278 + { 279 + struct st33zp24_platform_data *pdata; 280 + int ret; 281 + 282 + pdata = dev->dev.platform_data; 283 + if (!pdata) { 284 + dev_err(&dev->dev, "No platform data\n"); 285 + return -ENODEV; 286 + } 287 + 288 + /* store for late use */ 289 + phy->io_lpcpd = pdata->io_lpcpd; 290 + 291 + if (gpio_is_valid(pdata->io_lpcpd)) { 292 + ret = devm_gpio_request_one(&dev->dev, 293 + pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, 294 + "TPM IO_LPCPD"); 295 + if (ret) { 296 + dev_err(&dev->dev, "%s : reset gpio_request failed\n", 297 + __FILE__); 298 + return ret; 299 + } 300 + } 301 + 302 + return 0; 303 + } 304 + 305 + /* 306 + * tpm_st33_spi_probe initialize the TPM device 307 + * @param: dev, the spi_device drescription (TPM SPI description). 308 + * @return: 0 in case of success. 309 + * or a negative value describing the error. 310 + */ 311 + static int 312 + tpm_st33_spi_probe(struct spi_device *dev) 313 + { 314 + int ret; 315 + struct st33zp24_platform_data *pdata; 316 + struct st33zp24_spi_phy *phy; 317 + 318 + /* Check SPI platform functionnalities */ 319 + if (!dev) { 320 + pr_info("%s: dev is NULL. Device is not accessible.\n", 321 + __func__); 322 + return -ENODEV; 323 + } 324 + 325 + phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy), 326 + GFP_KERNEL); 327 + if (!phy) 328 + return -ENOMEM; 329 + 330 + phy->spi_device = dev; 331 + pdata = dev->dev.platform_data; 332 + if (!pdata && dev->dev.of_node) { 333 + ret = tpm_stm_spi_of_request_resources(phy); 334 + if (ret) 335 + return ret; 336 + } else if (pdata) { 337 + ret = tpm_stm_spi_request_resources(dev, phy); 338 + if (ret) 339 + return ret; 340 + } 341 + 342 + phy->spi_xfer.tx_buf = phy->tx_buf; 343 + phy->spi_xfer.rx_buf = phy->rx_buf; 344 + 345 + phy->latency = evaluate_latency(phy); 346 + if (phy->latency <= 0) 347 + return -ENODEV; 348 + 349 + return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq, 350 + phy->io_lpcpd); 351 + } 352 + 353 + /* 354 + * tpm_st33_spi_remove remove the TPM device 355 + * @param: client, the spi_device drescription (TPM SPI description). 356 + * @return: 0 in case of success. 357 + */ 358 + static int tpm_st33_spi_remove(struct spi_device *dev) 359 + { 360 + struct tpm_chip *chip = spi_get_drvdata(dev); 361 + 362 + return st33zp24_remove(chip); 363 + } 364 + 365 + #ifdef CONFIG_OF 366 + static const struct of_device_id of_st33zp24_spi_match[] = { 367 + { .compatible = "st,st33zp24-spi", }, 368 + {} 369 + }; 370 + MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match); 371 + #endif 372 + 373 + static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend, 374 + st33zp24_pm_resume); 375 + 376 + static struct spi_driver tpm_st33_spi_driver = { 377 + .driver = { 378 + .owner = THIS_MODULE, 379 + .name = TPM_ST33_SPI, 380 + .pm = &st33zp24_spi_ops, 381 + .of_match_table = of_match_ptr(of_st33zp24_spi_match), 382 + }, 383 + .probe = tpm_st33_spi_probe, 384 + .remove = tpm_st33_spi_remove, 385 + }; 386 + 387 + module_spi_driver(tpm_st33_spi_driver); 388 + 389 + MODULE_AUTHOR("TPM support (TPMsupport@list.st.com)"); 390 + MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver"); 391 + MODULE_VERSION("1.3.0"); 392 + MODULE_LICENSE("GPL");
+3
drivers/char/tpm/st33zp24/st33zp24.h
··· 18 18 #ifndef __LOCAL_ST33ZP24_H__ 19 19 #define __LOCAL_ST33ZP24_H__ 20 20 21 + #define TPM_WRITE_DIRECTION 0x80 22 + #define TPM_BUFSIZE 2048 23 + 21 24 struct st33zp24_phy_ops { 22 25 int (*send)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size); 23 26 int (*recv)(void *phy_id, u8 tpm_register, u8 *tpm_data, int tpm_size);