Re: [PATCH v4 3/4] tpm/st33zp24/spi: Add st33zp24 spi phy

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




Am Sonntag, 25. Januar 2015, 22:11:32 schrieb Christophe Ricard:
> st33zp24 TIS 1.2 support also SPI. It is using a proprietary protocol to
> transport TIS data.
> 
> Reviewed-by: Jason Gunthorpe <jason.gunthorpe@xxxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Christophe Ricard <christophe-h.ricard@xxxxxx>
> ---
>  drivers/char/tpm/st33zp24/Kconfig  |  10 +
>  drivers/char/tpm/st33zp24/Makefile |   3 +
>  drivers/char/tpm/st33zp24/spi.c    | 386
> +++++++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+)
>  create mode 100644 drivers/char/tpm/st33zp24/spi.c
> 
> diff --git a/drivers/char/tpm/st33zp24/Kconfig
> b/drivers/char/tpm/st33zp24/Kconfig index 51dcef5..09cb7278 100644
> --- a/drivers/char/tpm/st33zp24/Kconfig
> +++ b/drivers/char/tpm/st33zp24/Kconfig
> @@ -18,3 +18,13 @@ config TCG_TIS_ST33ZP24_I2C
>  	  ST33ZP24 with i2c interface.
>  	  To compile this driver as a module, choose M here; the module will be
>  	  called tpm_st33zp24_i2c.
> +
> +config TCG_TIS_ST33ZP24_SPI
> +	tristate "TPM 1.2 ST33ZP24 SPI support"
> +	depends on TCG_TIS_ST33ZP24
> +	depends on SPI
> +	---help---
> +	  This module adds support for the STMicroelectronics TPM security chip
> +	  ST33ZP24 with spi interface.
> +	  To compile this driver as a module, choose M here; the module will be
> +	  called tpm_st33zp24_spi.
> diff --git a/drivers/char/tpm/st33zp24/Makefile
> b/drivers/char/tpm/st33zp24/Makefile index 414497f..74a722e 100644
> --- a/drivers/char/tpm/st33zp24/Makefile
> +++ b/drivers/char/tpm/st33zp24/Makefile
> @@ -7,3 +7,6 @@ obj-$(CONFIG_TCG_TIS_ST33ZP24) += tpm_st33zp24.o
> 
>  tpm_st33zp24_i2c-objs = i2c.o
>  obj-$(CONFIG_TCG_TIS_ST33ZP24_I2C) += tpm_st33zp24_i2c.o
> +
> +tpm_st33zp24_spi-objs = spi.o
> +obj-$(CONFIG_TCG_TIS_ST33ZP24_SPI) += tpm_st33zp24_spi.o
> diff --git a/drivers/char/tpm/st33zp24/spi.c
> b/drivers/char/tpm/st33zp24/spi.c new file mode 100644
> index 0000000..d481478
> --- /dev/null
> +++ b/drivers/char/tpm/st33zp24/spi.c
> @@ -0,0 +1,386 @@
> +/*
> + * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24
> + * Copyright (C) 2009 - 2015  STMicroelectronics
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +#include <linux/gpio.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_gpio.h>
> +#include <linux/tpm.h>
> +#include <linux/platform_data/st33zp24.h>
> +
> +#include "st33zp24.h"
> +
> +#define TPM_DATA_FIFO           0x24
> +#define TPM_INTF_CAPABILITY     0x14
> +
> +#define TPM_DUMMY_BYTE		0x00
> +#define TPM_WRITE_DIRECTION	0x80
> +#define TPM_BUFSIZE		2048
see previous email :)
> +
> +#define MAX_SPI_LATENCY		15
> +#define LOCALITY0		0
> +
> +#define ST33ZP24_OK					0x5A
> +#define ST33ZP24_UNDEFINED_ERR				0x80
> +#define ST33ZP24_BADLOCALITY				0x81
> +#define ST33ZP24_TISREGISTER_UKNOWN			0x82
> +#define ST33ZP24_LOCALITY_NOT_ACTIVATED			0x83
> +#define ST33ZP24_HASH_END_BEFORE_HASH_START		0x84
> +#define ST33ZP24_BAD_COMMAND_ORDER			0x85
> +#define ST33ZP24_INCORECT_RECEIVED_LENGTH		0x86
> +#define ST33ZP24_TPM_FIFO_OVERFLOW			0x89
> +#define ST33ZP24_UNEXPECTED_READ_FIFO			0x8A
> +#define ST33ZP24_UNEXPECTED_WRITE_FIFO			0x8B
> +#define ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END	0x90
> +#define ST33ZP24_DUMMY_BYTES				0x00
> +
> +struct st33zp24_spi_phy {
> +	struct spi_device *spi_device;
> +	struct spi_transfer spi_xfer;
> +	int io_lpcpd;
> +	int latency;
> +};
> +
> +static int st33zp24_status_to_errno(u8 code)
> +{
> +	switch (code) {
> +	case ST33ZP24_OK:
> +		return 0;
> +	case ST33ZP24_UNDEFINED_ERR:
> +	case ST33ZP24_BADLOCALITY:
> +	case ST33ZP24_TISREGISTER_UKNOWN:
> +	case ST33ZP24_LOCALITY_NOT_ACTIVATED:
> +	case ST33ZP24_HASH_END_BEFORE_HASH_START:
> +	case ST33ZP24_BAD_COMMAND_ORDER:
> +	case ST33ZP24_UNEXPECTED_READ_FIFO:
> +	case ST33ZP24_UNEXPECTED_WRITE_FIFO:
> +	case ST33ZP24_CMDRDY_SET_WHEN_PROCESSING_HASH_END:
> +		return -EPROTO;
> +	case ST33ZP24_INCORECT_RECEIVED_LENGTH:
> +	case ST33ZP24_TPM_FIFO_OVERFLOW:
> +		return -EMSGSIZE;
> +	case ST33ZP24_DUMMY_BYTES:
> +	default:
> +		return -ENOSYS;
> +	}
> +}
> +
> +/*
> + * st33zp24_spi_send
> + * Send byte to the TIS register according to the ST33ZP24 SPI protocol.
> + * @param: tpm, the chip description
no such parameter :) 
> + * @param: tpm_register, the tpm tis register where the data should be
> written + * @param: tpm_data, the tpm_data to write inside the
> tpm_register + * @param: tpm_size, The length of the data
> + * @return: should be zero if success else a negative error code.
> + */
> +static int st33zp24_spi_send(void *phy_id, u8 tpm_register, u8 *tpm_data,
> +			     int tpm_size)
> +{
> +	u8 data = 0;
> +	int total_length = 0, nbr_dummy_bytes = 0, ret = 0;
> +	struct st33zp24_spi_phy *phy = phy_id;
> +	struct spi_device *dev = phy->spi_device;
> +	u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf;
> +	u8 *rx_buf = phy->spi_xfer.rx_buf;
> +
> +	/* Pre-Header */
> +	data = TPM_WRITE_DIRECTION | LOCALITY0;
> +	memcpy(tx_buf + total_length, &data, sizeof(data));
> +	total_length++;
> +	data = tpm_register;
> +	memcpy(tx_buf + total_length, &data, sizeof(data));
> +	total_length++;
> +
> +	if (tpm_size > 0 && tpm_register == TPM_DATA_FIFO) {
> +		tx_buf[total_length++] = tpm_size >> 8;
> +		tx_buf[total_length++] = tpm_size;
> +	}
> +
> +	memcpy(&tx_buf[total_length], tpm_data, tpm_size);
> +	total_length += tpm_size;
> +
> +	nbr_dummy_bytes = phy->latency;
> +	memset(&tx_buf[total_length], TPM_DUMMY_BYTE, nbr_dummy_bytes);
> +
> +	phy->spi_xfer.len = total_length + nbr_dummy_bytes;
> +
> +	ret = spi_sync_transfer(dev, &phy->spi_xfer, 1);
> +
> +	if (ret == 0)
> +		ret = rx_buf[total_length + nbr_dummy_bytes - 1];
> +
> +	return st33zp24_status_to_errno(ret);
> +} /* st33zp24_spi_send() */
> +
> +/*
> + * read8_recv
> + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
> + * @param: tpm, the chip description
no such parameter :) 
> + * @param: tpm_register, the tpm tis register where the data should be
> read + * @param: tpm_data, the TPM response
> + * @param: tpm_size, tpm TPM response size to read.
> + * @return: should be zero if success else a negative error code.
> + */
> +static int read8_reg(void *phy_id, u8 tpm_register, u8 *tpm_data, int
> tpm_size) +{
> +	u8 data = 0;
> +	int total_length = 0, nbr_dummy_bytes, ret;
> +	struct st33zp24_spi_phy *phy = phy_id;
> +	struct spi_device *dev = phy->spi_device;
> +	u8 *tx_buf = (u8 *)phy->spi_xfer.tx_buf;
> +	u8 *rx_buf = phy->spi_xfer.rx_buf;
> +
> +	/* Pre-Header */
> +	data = LOCALITY0;
> +	memcpy(tx_buf + total_length, &data, sizeof(data));
> +	total_length++;
> +	data = tpm_register;
> +	memcpy(tx_buf + total_length, &data, sizeof(data));
> +	total_length++;
> +
> +	nbr_dummy_bytes = phy->latency;
> +	memset(&tx_buf[total_length], TPM_DUMMY_BYTE,
> +	       nbr_dummy_bytes + tpm_size);
> +
> +	phy->spi_xfer.len = total_length + nbr_dummy_bytes + tpm_size;
> +
> +	/* header + status byte + size of the data + status byte */
> +	ret = spi_sync_transfer(dev, &phy->spi_xfer, 1);
> +	if (tpm_size > 0 && ret == 0) {
> +		ret = rx_buf[total_length + nbr_dummy_bytes - 1];
> +
> +		memcpy(tpm_data, rx_buf + total_length + nbr_dummy_bytes,
> +		       tpm_size);
> +	}
> +
> +	return ret;
> +} /* read8_reg() */
> +
> +/*
> + * st33zp24_spi_recv
> + * Recv byte from the TIS register according to the ST33ZP24 SPI protocol.
> + * @param: tpm, the chip description
no such parameter :) 
> + * @param: tpm_register, the tpm tis register where the data should be
> read + * @param: tpm_data, the TPM response
> + * @param: tpm_size, tpm TPM response size to read.
> + * @return: number of byte written successfully: should be one if success.
						 s ^^^^^^^ 
						   written on recv?
> + */
> +static int st33zp24_spi_recv(void *phy_id, u8 tpm_register, u8 *tpm_data,
> +			     int tpm_size)
> +{
> +	int ret;
> +
> +	ret = read8_reg(phy_id, tpm_register, tpm_data, tpm_size);
> +	if (!ret)
> +		return tpm_size;
> +	return ret;
> +} /* st33zp24_spi_recv() */
> +
> +static int evaluate_latency(void *phy_id)
> +{
> +	struct st33zp24_spi_phy *phy = phy_id;
> +	int latency = 1, status = 0;
> +	u8 data = 0;
> +
> +	while (!status && latency < MAX_SPI_LATENCY) {
> +		phy->latency = latency;
> +		status = read8_reg(phy_id, TPM_INTF_CAPABILITY, &data, 1);
> +		latency++;
> +	}
> +	return latency - 1;
why start at 1 and then deduce -1 at the end?

> +} /* evaluate_latency() */
> +
> +static const struct st33zp24_phy_ops spi_phy_ops = {
> +	.send = st33zp24_spi_send,
> +	.recv = st33zp24_spi_recv,
> +};
> +
> +#ifdef CONFIG_OF
> +static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy)
> +{
> +	struct device_node *pp;
> +	struct spi_device *dev = phy->spi_device;
> +	int gpio;
> +	int ret;
> +
> +	pp = dev->dev.of_node;
> +	if (!pp) {
> +		dev_err(&dev->dev, "No platform data\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Get GPIO from device tree */
> +	gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
> +	if (gpio < 0) {
> +		dev_err(&dev->dev,
> +			"Failed to retrieve lpcpd-gpios from dts.\n");
> +		phy->io_lpcpd = -1;
> +		/*
> +		 * lpcpd pin is not specified. This is not an issue as
> +		 * power management can be also managed by TPM specific
> +		 * commands. So leave with a success status code.
> +		 */
> +		return 0;
> +	}
> +	/* GPIO request and configuration */
> +	ret = devm_gpio_request_one(&dev->dev, gpio,
> +			GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
> +	if (ret) {
> +		dev_err(&dev->dev, "Failed to request lpcpd pin\n");
> +		return -ENODEV;
> +	}
> +	phy->io_lpcpd = gpio;
> +
> +	return 0;
> +}
> +#else
> +static int tpm_stm_spi_of_request_resources(struct st33zp24_spi_phy *phy)
> +{
> +	return -ENODEV;
> +}
> +#endif
> +
> +static int tpm_stm_spi_request_resources(struct spi_device *dev,
> +					 struct st33zp24_spi_phy *phy)
> +{
> +	struct st33zp24_platform_data *pdata;
> +	int ret;
> +
> +	pdata = dev->dev.platform_data;
> +	if (!pdata) {
> +		dev_err(&dev->dev, "No platform data\n");
> +		return -ENODEV;
> +	}
> +
> +	/* store for late use */
> +	phy->io_lpcpd = pdata->io_lpcpd;
> +
> +	if (gpio_is_valid(pdata->io_lpcpd)) {
> +		ret = devm_gpio_request_one(&dev->dev,
> +				pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
> +				"TPM IO_LPCPD");
> +		if (ret) {
> +			dev_err(&dev->dev, "%s : reset gpio_request failed\n",
> +				__FILE__);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * tpm_st33_spi_probe initialize the TPM device
> + * @param: client, the spi_device drescription (TPM SPI description).
> + * @param: id, the spi_device_id struct.
the params don't match the function below
so again no such parameters :) 
> + * @return: 0 in case of success.
> + *	 -1 in other case.
is this true? I guess not.
> + */
> +static int
> +tpm_st33_spi_probe(struct spi_device *dev)
> +{
> +	int ret;
> +	struct st33zp24_platform_data *pdata;
> +	struct st33zp24_spi_phy *phy;
> +
> +	/* Check SPI platform functionnalities */
> +	if (!dev) {
> +		pr_info("%s: dev is NULL. Device is not accessible.\n",
> +			__func__);
> +		return -ENODEV;
> +	}
> +
> +	phy = devm_kzalloc(&dev->dev, sizeof(struct st33zp24_spi_phy),
> +			   GFP_KERNEL);
> +	if (!phy)
> +		return -ENOMEM;
> +
> +	phy->spi_device = dev;
> +	pdata = dev->dev.platform_data;
> +	if (!pdata && dev->dev.of_node) {
> +		ret = tpm_stm_spi_of_request_resources(phy);
> +		if (ret)
> +			return ret;
> +	} else if (pdata) {
> +		ret = tpm_stm_spi_request_resources(dev, phy);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	phy->spi_xfer.tx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
> +					(TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) *
I don't get this calculation, why is this bugger so big?
> +					sizeof(u8), GFP_KERNEL);
sizeof(u8) can be removed.
> +	if (!phy->spi_xfer.tx_buf)
> +		return -ENOMEM;
> +
> +	phy->spi_xfer.rx_buf = devm_kmalloc(&dev->dev, (TPM_BUFSIZE +
> +					(TPM_BUFSIZE / 2) + TPM_DIGEST_SIZE) *
I don't get this calculation.
> +					sizeof(u8), GFP_KERNEL);

sizeof(u8) can be removed.
> +	if (!phy->spi_xfer.rx_buf)
> +		return -ENOMEM;
> +
> +	phy->latency = evaluate_latency(phy);
> +	if (phy->latency <= 0)
> +		return -ENODEV;
> +
> +	return st33zp24_probe(phy, &spi_phy_ops, &dev->dev, dev->irq,
> +			      phy->io_lpcpd);
> +}
> +
> +/*
> + * tpm_st33_spi_remove remove the TPM device
> + * @param: client, the spi_device drescription (TPM SPI description).
> + * @return: 0 in case of success.
> + */
> +static int tpm_st33_spi_remove(struct spi_device *dev)
> +{
> +	struct tpm_chip *chip = spi_get_drvdata(dev);
> +
> +	return st33zp24_remove(chip);
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id of_st33zp24_spi_match[] = {
> +	{ .compatible = "st,st33zp24-spi", },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match);
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(st33zp24_spi_ops, st33zp24_pm_suspend,
> +			 st33zp24_pm_resume);
> +
> +static struct spi_driver tpm_st33_spi_driver = {
> +	.driver = {
> +		.owner = THIS_MODULE,
> +		.name = TPM_ST33_SPI,
> +		.pm = &st33zp24_spi_ops,
> +		.of_match_table = of_match_ptr(of_st33zp24_spi_match),
> +	},
> +	.probe = tpm_st33_spi_probe,
> +	.remove = tpm_st33_spi_remove,
> +};
> +
> +module_spi_driver(tpm_st33_spi_driver);
> +
> +MODULE_AUTHOR("TPM support (TPMsupport@xxxxxxxxxxx)");
> +MODULE_DESCRIPTION("STM TPM 1.2 SPI ST33 Driver");
> +MODULE_VERSION("1.3.0");
> +MODULE_LICENSE("GPL");

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux