291 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP244 * Copyright (C) 2009 - 2016 STMicroelectronics5 */6 7#include <linux/module.h>8#include <linux/spi/spi.h>9#include <linux/of.h>10#include <linux/acpi.h>11#include <linux/tpm.h>12 13#include "../tpm.h"14#include "st33zp24.h"15 16#define TPM_DATA_FIFO 0x2417#define TPM_INTF_CAPABILITY 0x1418 19#define TPM_DUMMY_BYTE 0x0020 21#define MAX_SPI_LATENCY 1522#define LOCALITY0 023 24#define ST33ZP24_OK 0x5A25#define ST33ZP24_UNDEFINED_ERR 0x8026#define ST33ZP24_BADLOCALITY 0x8127#define ST33ZP24_TISREGISTER_UNKNOWN 0x8228#define ST33ZP24_LOCALITY_NOT_ACTIVATED 0x8329#define ST33ZP24_HASH_END_BEFORE_HASH_START 0x8430#define ST33ZP24_BAD_COMMAND_ORDER 0x8531#define ST33ZP24_INCORECT_RECEIVED_LENGTH 0x8632#define ST33ZP24_TPM_FIFO_OVERFLOW 0x8933#define ST33ZP24_UNEXPECTED_READ_FIFO 0x8A34#define ST33ZP24_UNEXPECTED_WRITE_FIFO 0x8B35#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END 0x9036#define ST33ZP24_DUMMY_BYTES 0x0037 38/*39 * TPM command can be up to 2048 byte, A TPM response can be up to40 * 1024 byte.41 * Between command and response, there are latency byte (up to 1542 * usually on st33zp24 2 are enough).43 *44 * Overall when sending a command and expecting an answer we need if45 * worst case:46 * 2048 (for the TPM command) + 1024 (for the TPM answer). We need47 * some latency byte before the answer is available (max 15).48 * We have 2048 + 1024 + 15.49 */50#define ST33ZP24_SPI_BUFFER_SIZE (ST33ZP24_BUFSIZE + (ST33ZP24_BUFSIZE / 2) +\51 MAX_SPI_LATENCY)52 53 54struct st33zp24_spi_phy {55 struct spi_device *spi_device;56 57 u8 tx_buf[ST33ZP24_SPI_BUFFER_SIZE];58 u8 rx_buf[ST33ZP24_SPI_BUFFER_SIZE];59 60 int latency;61};62 63static int st33zp24_status_to_errno(u8 code)64{65 switch (code) {66 case ST33ZP24_OK:67 return 0;68 case ST33ZP24_UNDEFINED_ERR:69 case ST33ZP24_BADLOCALITY:70 case ST33ZP24_TISREGISTER_UNKNOWN:71 case ST33ZP24_LOCALITY_NOT_ACTIVATED:72 case ST33ZP24_HASH_END_BEFORE_HASH_START:73 case ST33ZP24_BAD_COMMAND_ORDER:74 case ST33ZP24_UNEXPECTED_READ_FIFO:75 case ST33ZP24_UNEXPECTED_WRITE_FIFO:76 case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END:77 return -EPROTO;78 case ST33ZP24_INCORECT_RECEIVED_LENGTH:79 case ST33ZP24_TPM_FIFO_OVERFLOW:80 return -EMSGSIZE;81 case ST33ZP24_DUMMY_BYTES:82 return -ENOSYS;83 }84 return code;85}86 87/*88 * st33zp24_spi_send89 * Send byte to the TIS register according to the ST33ZP24 SPI protocol.90 * @param: phy_id, the phy description91 * @param: tpm_register, the tpm tis register where the data should be written92 * @param: tpm_data, the tpm_data to write inside the tpm_register93 * @param: tpm_size, The length of the data94 * @return: should be zero if success else a negative error code.95 */96static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data,97 int tpm_size)98{99 int total_length = 0, ret = 0;100 struct st33zp24_spi_phy *phy = phy_id;101 struct spi_device *dev = phy->spi_device;102 struct spi_transfer spi_xfer = {103 .tx_buf = phy->tx_buf,104 .rx_buf = phy->rx_buf,105 };106 107 /* Pre-Header */108 phy->tx_buf[total_length++] = TPM_WRITE_DIRECTION | LOCALITY0;109 phy->tx_buf[total_length++] = tpm_register;110 111 if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) {112 phy->tx_buf[total_length++] = tpm_size >> 8;113 phy->tx_buf[total_length++] = tpm_size;114 }115 116 memcpy(&phy->tx_buf[total_length], tpm_data, tpm_size);117 total_length += tpm_size;118 119 memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE, phy->latency);120 121 spi_xfer.len = total_length + phy->latency;122 123 ret = spi_sync_transfer(dev, &spi_xfer, 1);124 if (ret == 0)125 ret = phy->rx_buf[total_length + phy->latency - 1];126 127 return st33zp24_status_to_errno(ret);128} /* st33zp24_spi_send() */129 130/*131 * st33zp24_spi_read8_recv132 * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.133 * @param: phy_id, the phy description134 * @param: tpm_register, the tpm tis register where the data should be read135 * @param: tpm_data, the TPM response136 * @param: tpm_size, tpm TPM response size to read.137 * @return: should be zero if success else a negative error code.138 */139static int st33zp24_spi_read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data,140 int tpm_size)141{142 int total_length = 0, ret;143 struct st33zp24_spi_phy *phy = phy_id;144 struct spi_device *dev = phy->spi_device;145 struct spi_transfer spi_xfer = {146 .tx_buf = phy->tx_buf,147 .rx_buf = phy->rx_buf,148 };149 150 /* Pre-Header */151 phy->tx_buf[total_length++] = LOCALITY0;152 phy->tx_buf[total_length++] = tpm_register;153 154 memset(&phy->tx_buf[total_length], TPM_DUMMY_BYTE,155 phy->latency + tpm_size);156 157 spi_xfer.len = total_length + phy->latency + tpm_size;158 159 /* header + status byte + size of the data + status byte */160 ret = spi_sync_transfer(dev, &spi_xfer, 1);161 if (tpm_size > 0 && ret == 0) {162 ret = phy->rx_buf[total_length + phy->latency - 1];163 164 memcpy(tpm_data, phy->rx_buf + total_length + phy->latency,165 tpm_size);166 }167 168 return ret;169} /* st33zp24_spi_read8_reg() */170 171/*172 * st33zp24_spi_recv173 * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.174 * @param: phy_id, the phy description175 * @param: tpm_register, the tpm tis register where the data should be read176 * @param: tpm_data, the TPM response177 * @param: tpm_size, tpm TPM response size to read.178 * @return: number of byte read successfully: should be one if success.179 */180static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data,181 int tpm_size)182{183 int ret;184 185 ret = st33zp24_spi_read8_reg(phy_id, tpm_register, tpm_data, tpm_size);186 if (!st33zp24_status_to_errno(ret))187 return tpm_size;188 return ret;189} /* st33zp24_spi_recv() */190 191static int st33zp24_spi_evaluate_latency(void *phy_id)192{193 struct st33zp24_spi_phy *phy = phy_id;194 int latency = 1, status = 0;195 u8 data = 0;196 197 while (!status && latency < MAX_SPI_LATENCY) {198 phy->latency = latency;199 status = st33zp24_spi_read8_reg(phy_id, TPM_INTF_CAPABILITY,200 &data, 1);201 latency++;202 }203 if (status < 0)204 return status;205 if (latency == MAX_SPI_LATENCY)206 return -ENODEV;207 208 return latency - 1;209} /* evaluate_latency() */210 211static const struct st33zp24_phy_ops spi_phy_ops = {212 .send = st33zp24_spi_send,213 .recv = st33zp24_spi_recv,214};215 216/*217 * st33zp24_spi_probe initialize the TPM device218 * @param: dev, the spi_device description (TPM SPI description).219 * @return: 0 in case of success.220 * or a negative value describing the error.221 */222static int st33zp24_spi_probe(struct spi_device *dev)223{224 struct st33zp24_spi_phy *phy;225 226 phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy),227 GFP_KERNEL);228 if (!phy)229 return -ENOMEM;230 231 phy->spi_device = dev;232 233 phy->latency = st33zp24_spi_evaluate_latency(phy);234 if (phy->latency <= 0)235 return -ENODEV;236 237 return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq);238}239 240/*241 * st33zp24_spi_remove remove the TPM device242 * @param: client, the spi_device description (TPM SPI description).243 * @return: 0 in case of success.244 */245static void st33zp24_spi_remove(struct spi_device *dev)246{247 struct tpm_chip *chip = spi_get_drvdata(dev);248 249 st33zp24_remove(chip);250}251 252static const struct spi_device_id st33zp24_spi_id[] = {253 {TPM_ST33_SPI, 0},254 {}255};256MODULE_DEVICE_TABLE(spi, st33zp24_spi_id);257 258static const struct of_device_id of_st33zp24_spi_match[] __maybe_unused = {259 { .compatible = "st,st33zp24-spi", },260 {}261};262MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match);263 264static const struct acpi_device_id st33zp24_spi_acpi_match[] __maybe_unused = {265 {"SMO3324"},266 {}267};268MODULE_DEVICE_TABLE(acpi, st33zp24_spi_acpi_match);269 270static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend,271 st33zp24_pm_resume);272 273static struct spi_driver st33zp24_spi_driver = {274 .driver = {275 .name = "st33zp24-spi",276 .pm = &st33zp24_spi_ops,277 .of_match_table = of_match_ptr(of_st33zp24_spi_match),278 .acpi_match_table = ACPI_PTR(st33zp24_spi_acpi_match),279 },280 .probe = st33zp24_spi_probe,281 .remove = st33zp24_spi_remove,282 .id_table = st33zp24_spi_id,283};284 285module_spi_driver(st33zp24_spi_driver);286 287MODULE_AUTHOR("TPM support <TPMsupport@list.st.com>");288MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver");289MODULE_VERSION("1.3.0");290MODULE_LICENSE("GPL");291