// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2020 Google Inc. * * Based on Infineon TPM driver by Peter Huewe. * * cr50 is a firmware for H1 secure modules that requires special * handling for the I2C interface. * * - Use an interrupt for transaction status instead of hardcoded delays. * - Must use write+wait+read read protocol. * - All 4 bytes of status register must be read/written at once. * - Burst count max is 63 bytes, and burst count behaves slightly differently * than other I2C TPMs. * - When reading from FIFO the full burstcnt must be read instead of just * reading header and determining the remainder. */ #include <linux/acpi.h> #include <linux/completion.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/slab.h> #include <linux/wait.h> #include "tpm_tis_core.h" #define TPM_CR50_MAX_BUFSIZE … #define TPM_CR50_TIMEOUT_SHORT_MS … #define TPM_CR50_TIMEOUT_NOIRQ_MS … #define TPM_CR50_I2C_DID_VID … #define TPM_TI50_I2C_DID_VID … #define TPM_CR50_I2C_MAX_RETRIES … #define TPM_CR50_I2C_RETRY_DELAY_LO … #define TPM_CR50_I2C_RETRY_DELAY_HI … #define TPM_I2C_ACCESS(l) … #define TPM_I2C_STS(l) … #define TPM_I2C_DATA_FIFO(l) … #define TPM_I2C_DID_VID(l) … /** * struct tpm_i2c_cr50_priv_data - Driver private data. * @irq: Irq number used for this chip. * If irq <= 0, then a fixed timeout is used instead of waiting for irq. * @tpm_ready: Struct used by irq handler to signal R/W readiness. * @buf: Buffer used for i2c writes, with i2c address prepended to content. * * Private driver struct used by kernel threads and interrupt context. */ struct tpm_i2c_cr50_priv_data { … }; /** * tpm_cr50_i2c_int_handler() - cr50 interrupt handler. * @dummy: Unused parameter. * @tpm_info: TPM chip information. * * The cr50 interrupt handler signals waiting threads that the * interrupt has been asserted. It does not do any interrupt triggered * processing but is instead used to avoid fixed delays. * * Return: * IRQ_HANDLED signifies irq was handled by this device. */ static irqreturn_t tpm_cr50_i2c_int_handler(int dummy, void *tpm_info) { … } /** * tpm_cr50_i2c_wait_tpm_ready() - Wait for tpm to signal ready. * @chip: A TPM chip. * * Wait for completion interrupt if available, otherwise use a fixed * delay for the TPM to be ready. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_wait_tpm_ready(struct tpm_chip *chip) { … } /** * tpm_cr50_i2c_enable_tpm_irq() - Enable TPM irq. * @chip: A TPM chip. */ static void tpm_cr50_i2c_enable_tpm_irq(struct tpm_chip *chip) { … } /** * tpm_cr50_i2c_disable_tpm_irq() - Disable TPM irq. * @chip: A TPM chip. */ static void tpm_cr50_i2c_disable_tpm_irq(struct tpm_chip *chip) { … } /** * tpm_cr50_i2c_transfer_message() - Transfer a message over i2c. * @dev: Device information. * @adapter: I2C adapter. * @msg: Message to transfer. * * Call unlocked i2c transfer routine with the provided parameters and * retry in case of bus errors. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_transfer_message(struct device *dev, struct i2c_adapter *adapter, struct i2c_msg *msg) { … } /** * tpm_cr50_i2c_read() - Read from TPM register. * @chip: A TPM chip. * @addr: Register address to read from. * @buffer: Read destination, provided by caller. * @len: Number of bytes to read. * * Sends the register address byte to the TPM, then waits until TPM * is ready via interrupt signal or timeout expiration, then 'len' * bytes are read from TPM response into the provided 'buffer'. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_read(struct tpm_chip *chip, u8 addr, u8 *buffer, size_t len) { … } /** * tpm_cr50_i2c_write()- Write to TPM register. * @chip: A TPM chip. * @addr: Register address to write to. * @buffer: Data to write. * @len: Number of bytes to write. * * The provided address is prepended to the data in 'buffer', the * combined address+data is sent to the TPM, then wait for TPM to * indicate it is done writing. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_write(struct tpm_chip *chip, u8 addr, u8 *buffer, size_t len) { … } /** * tpm_cr50_check_locality() - Verify TPM locality 0 is active. * @chip: A TPM chip. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_check_locality(struct tpm_chip *chip) { … } /** * tpm_cr50_release_locality() - Release TPM locality. * @chip: A TPM chip. * @force: Flag to force release if set. */ static void tpm_cr50_release_locality(struct tpm_chip *chip, bool force) { … } /** * tpm_cr50_request_locality() - Request TPM locality 0. * @chip: A TPM chip. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_request_locality(struct tpm_chip *chip) { … } /** * tpm_cr50_i2c_tis_status() - Read cr50 tis status. * @chip: A TPM chip. * * cr50 requires all 4 bytes of status register to be read. * * Return: * TPM status byte. */ static u8 tpm_cr50_i2c_tis_status(struct tpm_chip *chip) { … } /** * tpm_cr50_i2c_tis_set_ready() - Set status register to ready. * @chip: A TPM chip. * * cr50 requires all 4 bytes of status register to be written. */ static void tpm_cr50_i2c_tis_set_ready(struct tpm_chip *chip) { … } /** * tpm_cr50_i2c_get_burst_and_status() - Get burst count and status. * @chip: A TPM chip. * @mask: Status mask. * @burst: Return value for burst. * @status: Return value for status. * * cr50 uses bytes 3:2 of status register for burst count and * all 4 bytes must be read. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_get_burst_and_status(struct tpm_chip *chip, u8 mask, size_t *burst, u32 *status) { … } /** * tpm_cr50_i2c_tis_recv() - TPM reception callback. * @chip: A TPM chip. * @buf: Reception buffer. * @buf_len: Buffer length to read. * * Return: * - >= 0: Number of read bytes. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_tis_recv(struct tpm_chip *chip, u8 *buf, size_t buf_len) { … } /** * tpm_cr50_i2c_tis_send() - TPM transmission callback. * @chip: A TPM chip. * @buf: Buffer to send. * @len: Buffer length. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) { … } /** * tpm_cr50_i2c_req_canceled() - Callback to notify a request cancel. * @chip: A TPM chip. * @status: Status given by the cancel callback. * * Return: * True if command is ready, False otherwise. */ static bool tpm_cr50_i2c_req_canceled(struct tpm_chip *chip, u8 status) { … } static bool tpm_cr50_i2c_is_firmware_power_managed(struct device *dev) { … } static const struct tpm_class_ops cr50_i2c = …; #ifdef CONFIG_ACPI static const struct acpi_device_id cr50_i2c_acpi_id[] = …; MODULE_DEVICE_TABLE(acpi, cr50_i2c_acpi_id); #endif #ifdef CONFIG_OF static const struct of_device_id of_cr50_i2c_match[] = …; MODULE_DEVICE_TABLE(of, of_cr50_i2c_match); #endif /** * tpm_cr50_i2c_probe() - Driver probe function. * @client: I2C client information. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static int tpm_cr50_i2c_probe(struct i2c_client *client) { … } /** * tpm_cr50_i2c_remove() - Driver remove function. * @client: I2C client information. * * Return: * - 0: Success. * - -errno: A POSIX error code. */ static void tpm_cr50_i2c_remove(struct i2c_client *client) { … } static SIMPLE_DEV_PM_OPS(cr50_i2c_pm, tpm_pm_suspend, tpm_pm_resume); static struct i2c_driver cr50_i2c_driver = …; module_i2c_driver(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;