linux/drivers/char/tpm/tpm_tis_i2c_cr50.c

// 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();