18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ATMEL I2C TPM AT97SC3204T 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 V Lab Technologies 68c2ecf20Sopenharmony_ci * Teddy Reed <teddy@prosauce.org> 78c2ecf20Sopenharmony_ci * Copyright (C) 2013, Obsidian Research Corp. 88c2ecf20Sopenharmony_ci * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> 98c2ecf20Sopenharmony_ci * Device driver for ATMEL I2C TPMs. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Teddy Reed determined the basic I2C command flow, unlike other I2C TPM 128c2ecf20Sopenharmony_ci * devices the raw TCG formatted TPM command data is written via I2C and then 138c2ecf20Sopenharmony_ci * raw TCG formatted TPM command data is returned via I2C. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * TGC status/locality/etc functions seen in the LPC implementation do not 168c2ecf20Sopenharmony_ci * seem to be present. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/i2c.h> 238c2ecf20Sopenharmony_ci#include "tpm.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define I2C_DRIVER_NAME "tpm_i2c_atmel" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define TPM_I2C_SHORT_TIMEOUT 750 /* ms */ 288c2ecf20Sopenharmony_ci#define TPM_I2C_LONG_TIMEOUT 2000 /* 2 sec */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define ATMEL_STS_OK 1 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct priv_data { 338c2ecf20Sopenharmony_ci size_t len; 348c2ecf20Sopenharmony_ci /* This is the amount we read on the first try. 25 was chosen to fit a 358c2ecf20Sopenharmony_ci * fair number of read responses in the buffer so a 2nd retry can be 368c2ecf20Sopenharmony_ci * avoided in small message cases. */ 378c2ecf20Sopenharmony_ci u8 buffer[sizeof(struct tpm_header) + 25]; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct priv_data *priv = dev_get_drvdata(&chip->dev); 438c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(chip->dev.parent); 448c2ecf20Sopenharmony_ci s32 status; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci priv->len = 0; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (len <= 2) 498c2ecf20Sopenharmony_ci return -EIO; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci status = i2c_master_send(client, buf, len); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci dev_dbg(&chip->dev, 548c2ecf20Sopenharmony_ci "%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, 558c2ecf20Sopenharmony_ci (int)min_t(size_t, 64, len), buf, len, status); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (status < 0) 588c2ecf20Sopenharmony_ci return status; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* The upper layer does not support incomplete sends. */ 618c2ecf20Sopenharmony_ci if (status != len) 628c2ecf20Sopenharmony_ci return -E2BIG; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct priv_data *priv = dev_get_drvdata(&chip->dev); 708c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(chip->dev.parent); 718c2ecf20Sopenharmony_ci struct tpm_header *hdr = (struct tpm_header *)priv->buffer; 728c2ecf20Sopenharmony_ci u32 expected_len; 738c2ecf20Sopenharmony_ci int rc; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (priv->len == 0) 768c2ecf20Sopenharmony_ci return -EIO; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Get the message size from the message header, if we didn't get the 798c2ecf20Sopenharmony_ci * whole message in read_status then we need to re-read the 808c2ecf20Sopenharmony_ci * message. */ 818c2ecf20Sopenharmony_ci expected_len = be32_to_cpu(hdr->length); 828c2ecf20Sopenharmony_ci if (expected_len > count) 838c2ecf20Sopenharmony_ci return -ENOMEM; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (priv->len >= expected_len) { 868c2ecf20Sopenharmony_ci dev_dbg(&chip->dev, 878c2ecf20Sopenharmony_ci "%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__, 888c2ecf20Sopenharmony_ci (int)min_t(size_t, 64, expected_len), buf, count, 898c2ecf20Sopenharmony_ci expected_len); 908c2ecf20Sopenharmony_ci memcpy(buf, priv->buffer, expected_len); 918c2ecf20Sopenharmony_ci return expected_len; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci rc = i2c_master_recv(client, buf, expected_len); 958c2ecf20Sopenharmony_ci dev_dbg(&chip->dev, 968c2ecf20Sopenharmony_ci "%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__, 978c2ecf20Sopenharmony_ci (int)min_t(size_t, 64, expected_len), buf, count, 988c2ecf20Sopenharmony_ci expected_len); 998c2ecf20Sopenharmony_ci return rc; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic void i2c_atmel_cancel(struct tpm_chip *chip) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci dev_err(&chip->dev, "TPM operation cancellation was requested, but is not supported"); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic u8 i2c_atmel_read_status(struct tpm_chip *chip) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct priv_data *priv = dev_get_drvdata(&chip->dev); 1108c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(chip->dev.parent); 1118c2ecf20Sopenharmony_ci int rc; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* The TPM fails the I2C read until it is ready, so we do the entire 1148c2ecf20Sopenharmony_ci * transfer here and buffer it locally. This way the common code can 1158c2ecf20Sopenharmony_ci * properly handle the timeouts. */ 1168c2ecf20Sopenharmony_ci priv->len = 0; 1178c2ecf20Sopenharmony_ci memset(priv->buffer, 0, sizeof(priv->buffer)); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Once the TPM has completed the command the command remains readable 1218c2ecf20Sopenharmony_ci * until another command is issued. */ 1228c2ecf20Sopenharmony_ci rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer)); 1238c2ecf20Sopenharmony_ci dev_dbg(&chip->dev, 1248c2ecf20Sopenharmony_ci "%s: sts=%d", __func__, rc); 1258c2ecf20Sopenharmony_ci if (rc <= 0) 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci priv->len = rc; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return ATMEL_STS_OK; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci return false; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic const struct tpm_class_ops i2c_atmel = { 1398c2ecf20Sopenharmony_ci .flags = TPM_OPS_AUTO_STARTUP, 1408c2ecf20Sopenharmony_ci .status = i2c_atmel_read_status, 1418c2ecf20Sopenharmony_ci .recv = i2c_atmel_recv, 1428c2ecf20Sopenharmony_ci .send = i2c_atmel_send, 1438c2ecf20Sopenharmony_ci .cancel = i2c_atmel_cancel, 1448c2ecf20Sopenharmony_ci .req_complete_mask = ATMEL_STS_OK, 1458c2ecf20Sopenharmony_ci .req_complete_val = ATMEL_STS_OK, 1468c2ecf20Sopenharmony_ci .req_canceled = i2c_atmel_req_canceled, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int i2c_atmel_probe(struct i2c_client *client, 1508c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct tpm_chip *chip; 1538c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 1548c2ecf20Sopenharmony_ci struct priv_data *priv; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 1578c2ecf20Sopenharmony_ci return -ENODEV; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci chip = tpmm_chip_alloc(dev, &i2c_atmel); 1608c2ecf20Sopenharmony_ci if (IS_ERR(chip)) 1618c2ecf20Sopenharmony_ci return PTR_ERR(chip); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); 1648c2ecf20Sopenharmony_ci if (!priv) 1658c2ecf20Sopenharmony_ci return -ENOMEM; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Default timeouts */ 1688c2ecf20Sopenharmony_ci chip->timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); 1698c2ecf20Sopenharmony_ci chip->timeout_b = msecs_to_jiffies(TPM_I2C_LONG_TIMEOUT); 1708c2ecf20Sopenharmony_ci chip->timeout_c = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); 1718c2ecf20Sopenharmony_ci chip->timeout_d = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci dev_set_drvdata(&chip->dev, priv); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* There is no known way to probe for this device, and all version 1768c2ecf20Sopenharmony_ci * information seems to be read via TPM commands. Thus we rely on the 1778c2ecf20Sopenharmony_ci * TPM startup process in the common code to detect the device. */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return tpm_chip_register(chip); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int i2c_atmel_remove(struct i2c_client *client) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct device *dev = &(client->dev); 1858c2ecf20Sopenharmony_ci struct tpm_chip *chip = dev_get_drvdata(dev); 1868c2ecf20Sopenharmony_ci tpm_chip_unregister(chip); 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic const struct i2c_device_id i2c_atmel_id[] = { 1918c2ecf20Sopenharmony_ci {I2C_DRIVER_NAME, 0}, 1928c2ecf20Sopenharmony_ci {} 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, i2c_atmel_id); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 1978c2ecf20Sopenharmony_cistatic const struct of_device_id i2c_atmel_of_match[] = { 1988c2ecf20Sopenharmony_ci {.compatible = "atmel,at97sc3204t"}, 1998c2ecf20Sopenharmony_ci {}, 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, i2c_atmel_of_match); 2028c2ecf20Sopenharmony_ci#endif 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(i2c_atmel_pm_ops, tpm_pm_suspend, tpm_pm_resume); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic struct i2c_driver i2c_atmel_driver = { 2078c2ecf20Sopenharmony_ci .id_table = i2c_atmel_id, 2088c2ecf20Sopenharmony_ci .probe = i2c_atmel_probe, 2098c2ecf20Sopenharmony_ci .remove = i2c_atmel_remove, 2108c2ecf20Sopenharmony_ci .driver = { 2118c2ecf20Sopenharmony_ci .name = I2C_DRIVER_NAME, 2128c2ecf20Sopenharmony_ci .pm = &i2c_atmel_pm_ops, 2138c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(i2c_atmel_of_match), 2148c2ecf20Sopenharmony_ci }, 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cimodule_i2c_driver(i2c_atmel_driver); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jason Gunthorpe <jgunthorpe@obsidianresearch.com>"); 2208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Atmel TPM I2C Driver"); 2218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 222