brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · 5149231 Raw
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