18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) Microsoft Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Implements a firmware TPM as described here:
68c2ecf20Sopenharmony_ci * https://www.microsoft.com/en-us/research/publication/ftpm-software-implementation-tpm-chip/
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * A reference implementation is available here:
98c2ecf20Sopenharmony_ci * https://github.com/microsoft/ms-tpm-20-ref/tree/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/acpi.h>
138c2ecf20Sopenharmony_ci#include <linux/of.h>
148c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
168c2ecf20Sopenharmony_ci#include <linux/tee_drv.h>
178c2ecf20Sopenharmony_ci#include <linux/tpm.h>
188c2ecf20Sopenharmony_ci#include <linux/uuid.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "tpm.h"
218c2ecf20Sopenharmony_ci#include "tpm_ftpm_tee.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * TA_FTPM_UUID: BC50D971-D4C9-42C4-82CB-343FB7F37896
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Randomly generated, and must correspond to the GUID on the TA side.
278c2ecf20Sopenharmony_ci * Defined here in the reference implementation:
288c2ecf20Sopenharmony_ci * https://github.com/microsoft/ms-tpm-20-ref/blob/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM/include/fTPM.h#L42
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_cistatic const uuid_t ftpm_ta_uuid =
318c2ecf20Sopenharmony_ci	UUID_INIT(0xBC50D971, 0xD4C9, 0x42C4,
328c2ecf20Sopenharmony_ci		  0x82, 0xCB, 0x34, 0x3F, 0xB7, 0xF3, 0x78, 0x96);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/**
358c2ecf20Sopenharmony_ci * ftpm_tee_tpm_op_recv() - retrieve fTPM response.
368c2ecf20Sopenharmony_ci * @chip:	the tpm_chip description as specified in driver/char/tpm/tpm.h.
378c2ecf20Sopenharmony_ci * @buf:	the buffer to store data.
388c2ecf20Sopenharmony_ci * @count:	the number of bytes to read.
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * Return:
418c2ecf20Sopenharmony_ci *	In case of success the number of bytes received.
428c2ecf20Sopenharmony_ci *	On failure, -errno.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_cistatic int ftpm_tee_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
478c2ecf20Sopenharmony_ci	size_t len;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	len = pvt_data->resp_len;
508c2ecf20Sopenharmony_ci	if (count < len) {
518c2ecf20Sopenharmony_ci		dev_err(&chip->dev,
528c2ecf20Sopenharmony_ci			"%s: Invalid size in recv: count=%zd, resp_len=%zd\n",
538c2ecf20Sopenharmony_ci			__func__, count, len);
548c2ecf20Sopenharmony_ci		return -EIO;
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	memcpy(buf, pvt_data->resp_buf, len);
588c2ecf20Sopenharmony_ci	pvt_data->resp_len = 0;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return len;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/**
648c2ecf20Sopenharmony_ci * ftpm_tee_tpm_op_send() - send TPM commands through the TEE shared memory.
658c2ecf20Sopenharmony_ci * @chip:	the tpm_chip description as specified in driver/char/tpm/tpm.h
668c2ecf20Sopenharmony_ci * @buf:	the buffer to send.
678c2ecf20Sopenharmony_ci * @len:	the number of bytes to send.
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * Return:
708c2ecf20Sopenharmony_ci *	In case of success, returns 0.
718c2ecf20Sopenharmony_ci *	On failure, -errno
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistatic int ftpm_tee_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t len)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
768c2ecf20Sopenharmony_ci	size_t resp_len;
778c2ecf20Sopenharmony_ci	int rc;
788c2ecf20Sopenharmony_ci	u8 *temp_buf;
798c2ecf20Sopenharmony_ci	struct tpm_header *resp_header;
808c2ecf20Sopenharmony_ci	struct tee_ioctl_invoke_arg transceive_args;
818c2ecf20Sopenharmony_ci	struct tee_param command_params[4];
828c2ecf20Sopenharmony_ci	struct tee_shm *shm = pvt_data->shm;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (len > MAX_COMMAND_SIZE) {
858c2ecf20Sopenharmony_ci		dev_err(&chip->dev,
868c2ecf20Sopenharmony_ci			"%s: len=%zd exceeds MAX_COMMAND_SIZE supported by fTPM TA\n",
878c2ecf20Sopenharmony_ci			__func__, len);
888c2ecf20Sopenharmony_ci		return -EIO;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	memset(&transceive_args, 0, sizeof(transceive_args));
928c2ecf20Sopenharmony_ci	memset(command_params, 0, sizeof(command_params));
938c2ecf20Sopenharmony_ci	pvt_data->resp_len = 0;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of fTPM TA */
968c2ecf20Sopenharmony_ci	transceive_args = (struct tee_ioctl_invoke_arg) {
978c2ecf20Sopenharmony_ci		.func = FTPM_OPTEE_TA_SUBMIT_COMMAND,
988c2ecf20Sopenharmony_ci		.session = pvt_data->session,
998c2ecf20Sopenharmony_ci		.num_params = 4,
1008c2ecf20Sopenharmony_ci	};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */
1038c2ecf20Sopenharmony_ci	command_params[0] = (struct tee_param) {
1048c2ecf20Sopenharmony_ci		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
1058c2ecf20Sopenharmony_ci		.u.memref = {
1068c2ecf20Sopenharmony_ci			.shm = shm,
1078c2ecf20Sopenharmony_ci			.size = len,
1088c2ecf20Sopenharmony_ci			.shm_offs = 0,
1098c2ecf20Sopenharmony_ci		},
1108c2ecf20Sopenharmony_ci	};
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	temp_buf = tee_shm_get_va(shm, 0);
1138c2ecf20Sopenharmony_ci	if (IS_ERR(temp_buf)) {
1148c2ecf20Sopenharmony_ci		dev_err(&chip->dev, "%s: tee_shm_get_va failed for transmit\n",
1158c2ecf20Sopenharmony_ci			__func__);
1168c2ecf20Sopenharmony_ci		return PTR_ERR(temp_buf);
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci	memset(temp_buf, 0, (MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE));
1198c2ecf20Sopenharmony_ci	memcpy(temp_buf, buf, len);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	command_params[1] = (struct tee_param) {
1228c2ecf20Sopenharmony_ci		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
1238c2ecf20Sopenharmony_ci		.u.memref = {
1248c2ecf20Sopenharmony_ci			.shm = shm,
1258c2ecf20Sopenharmony_ci			.size = MAX_RESPONSE_SIZE,
1268c2ecf20Sopenharmony_ci			.shm_offs = MAX_COMMAND_SIZE,
1278c2ecf20Sopenharmony_ci		},
1288c2ecf20Sopenharmony_ci	};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	rc = tee_client_invoke_func(pvt_data->ctx, &transceive_args,
1318c2ecf20Sopenharmony_ci				    command_params);
1328c2ecf20Sopenharmony_ci	if ((rc < 0) || (transceive_args.ret != 0)) {
1338c2ecf20Sopenharmony_ci		dev_err(&chip->dev, "%s: SUBMIT_COMMAND invoke error: 0x%x\n",
1348c2ecf20Sopenharmony_ci			__func__, transceive_args.ret);
1358c2ecf20Sopenharmony_ci		return (rc < 0) ? rc : transceive_args.ret;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
1398c2ecf20Sopenharmony_ci	if (IS_ERR(temp_buf)) {
1408c2ecf20Sopenharmony_ci		dev_err(&chip->dev, "%s: tee_shm_get_va failed for receive\n",
1418c2ecf20Sopenharmony_ci			__func__);
1428c2ecf20Sopenharmony_ci		return PTR_ERR(temp_buf);
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	resp_header = (struct tpm_header *)temp_buf;
1468c2ecf20Sopenharmony_ci	resp_len = be32_to_cpu(resp_header->length);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	/* sanity check resp_len */
1498c2ecf20Sopenharmony_ci	if (resp_len < TPM_HEADER_SIZE) {
1508c2ecf20Sopenharmony_ci		dev_err(&chip->dev, "%s: tpm response header too small\n",
1518c2ecf20Sopenharmony_ci			__func__);
1528c2ecf20Sopenharmony_ci		return -EIO;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci	if (resp_len > MAX_RESPONSE_SIZE) {
1558c2ecf20Sopenharmony_ci		dev_err(&chip->dev,
1568c2ecf20Sopenharmony_ci			"%s: resp_len=%zd exceeds MAX_RESPONSE_SIZE\n",
1578c2ecf20Sopenharmony_ci			__func__, resp_len);
1588c2ecf20Sopenharmony_ci		return -EIO;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* sanity checks look good, cache the response */
1628c2ecf20Sopenharmony_ci	memcpy(pvt_data->resp_buf, temp_buf, resp_len);
1638c2ecf20Sopenharmony_ci	pvt_data->resp_len = resp_len;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic void ftpm_tee_tpm_op_cancel(struct tpm_chip *chip)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	/* not supported */
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic u8 ftpm_tee_tpm_op_status(struct tpm_chip *chip)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic bool ftpm_tee_tpm_req_canceled(struct tpm_chip *chip, u8 status)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	return 0;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic const struct tpm_class_ops ftpm_tee_tpm_ops = {
1848c2ecf20Sopenharmony_ci	.flags = TPM_OPS_AUTO_STARTUP,
1858c2ecf20Sopenharmony_ci	.recv = ftpm_tee_tpm_op_recv,
1868c2ecf20Sopenharmony_ci	.send = ftpm_tee_tpm_op_send,
1878c2ecf20Sopenharmony_ci	.cancel = ftpm_tee_tpm_op_cancel,
1888c2ecf20Sopenharmony_ci	.status = ftpm_tee_tpm_op_status,
1898c2ecf20Sopenharmony_ci	.req_complete_mask = 0,
1908c2ecf20Sopenharmony_ci	.req_complete_val = 0,
1918c2ecf20Sopenharmony_ci	.req_canceled = ftpm_tee_tpm_req_canceled,
1928c2ecf20Sopenharmony_ci};
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/*
1958c2ecf20Sopenharmony_ci * Check whether this driver supports the fTPM TA in the TEE instance
1968c2ecf20Sopenharmony_ci * represented by the params (ver/data) to this function.
1978c2ecf20Sopenharmony_ci */
1988c2ecf20Sopenharmony_cistatic int ftpm_tee_match(struct tee_ioctl_version_data *ver, const void *data)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	/*
2018c2ecf20Sopenharmony_ci	 * Currently this driver only support GP Complaint OPTEE based fTPM TA
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
2048c2ecf20Sopenharmony_ci		(ver->gen_caps & TEE_GEN_CAP_GP))
2058c2ecf20Sopenharmony_ci		return 1;
2068c2ecf20Sopenharmony_ci	else
2078c2ecf20Sopenharmony_ci		return 0;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/**
2118c2ecf20Sopenharmony_ci * ftpm_tee_probe() - initialize the fTPM
2128c2ecf20Sopenharmony_ci * @pdev: the platform_device description.
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Return:
2158c2ecf20Sopenharmony_ci *	On success, 0. On failure, -errno.
2168c2ecf20Sopenharmony_ci */
2178c2ecf20Sopenharmony_cistatic int ftpm_tee_probe(struct device *dev)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	int rc;
2208c2ecf20Sopenharmony_ci	struct tpm_chip *chip;
2218c2ecf20Sopenharmony_ci	struct ftpm_tee_private *pvt_data = NULL;
2228c2ecf20Sopenharmony_ci	struct tee_ioctl_open_session_arg sess_arg;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	pvt_data = devm_kzalloc(dev, sizeof(struct ftpm_tee_private),
2258c2ecf20Sopenharmony_ci				GFP_KERNEL);
2268c2ecf20Sopenharmony_ci	if (!pvt_data)
2278c2ecf20Sopenharmony_ci		return -ENOMEM;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, pvt_data);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* Open context with TEE driver */
2328c2ecf20Sopenharmony_ci	pvt_data->ctx = tee_client_open_context(NULL, ftpm_tee_match, NULL,
2338c2ecf20Sopenharmony_ci						NULL);
2348c2ecf20Sopenharmony_ci	if (IS_ERR(pvt_data->ctx)) {
2358c2ecf20Sopenharmony_ci		if (PTR_ERR(pvt_data->ctx) == -ENOENT)
2368c2ecf20Sopenharmony_ci			return -EPROBE_DEFER;
2378c2ecf20Sopenharmony_ci		dev_err(dev, "%s: tee_client_open_context failed\n", __func__);
2388c2ecf20Sopenharmony_ci		return PTR_ERR(pvt_data->ctx);
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* Open a session with fTPM TA */
2428c2ecf20Sopenharmony_ci	memset(&sess_arg, 0, sizeof(sess_arg));
2438c2ecf20Sopenharmony_ci	export_uuid(sess_arg.uuid, &ftpm_ta_uuid);
2448c2ecf20Sopenharmony_ci	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
2458c2ecf20Sopenharmony_ci	sess_arg.num_params = 0;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	rc = tee_client_open_session(pvt_data->ctx, &sess_arg, NULL);
2488c2ecf20Sopenharmony_ci	if ((rc < 0) || (sess_arg.ret != 0)) {
2498c2ecf20Sopenharmony_ci		dev_err(dev, "%s: tee_client_open_session failed, err=%x\n",
2508c2ecf20Sopenharmony_ci			__func__, sess_arg.ret);
2518c2ecf20Sopenharmony_ci		rc = -EINVAL;
2528c2ecf20Sopenharmony_ci		goto out_tee_session;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci	pvt_data->session = sess_arg.session;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	/* Allocate dynamic shared memory with fTPM TA */
2578c2ecf20Sopenharmony_ci	pvt_data->shm = tee_shm_alloc_kernel_buf(pvt_data->ctx,
2588c2ecf20Sopenharmony_ci						 MAX_COMMAND_SIZE +
2598c2ecf20Sopenharmony_ci						 MAX_RESPONSE_SIZE);
2608c2ecf20Sopenharmony_ci	if (IS_ERR(pvt_data->shm)) {
2618c2ecf20Sopenharmony_ci		dev_err(dev, "%s: tee_shm_alloc_kernel_buf failed\n", __func__);
2628c2ecf20Sopenharmony_ci		rc = -ENOMEM;
2638c2ecf20Sopenharmony_ci		goto out_shm_alloc;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/* Allocate new struct tpm_chip instance */
2678c2ecf20Sopenharmony_ci	chip = tpm_chip_alloc(dev, &ftpm_tee_tpm_ops);
2688c2ecf20Sopenharmony_ci	if (IS_ERR(chip)) {
2698c2ecf20Sopenharmony_ci		dev_err(dev, "%s: tpm_chip_alloc failed\n", __func__);
2708c2ecf20Sopenharmony_ci		rc = PTR_ERR(chip);
2718c2ecf20Sopenharmony_ci		goto out_chip_alloc;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	pvt_data->chip = chip;
2758c2ecf20Sopenharmony_ci	pvt_data->chip->flags |= TPM_CHIP_FLAG_TPM2;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* Create a character device for the fTPM */
2788c2ecf20Sopenharmony_ci	rc = tpm_chip_register(pvt_data->chip);
2798c2ecf20Sopenharmony_ci	if (rc) {
2808c2ecf20Sopenharmony_ci		dev_err(dev, "%s: tpm_chip_register failed with rc=%d\n",
2818c2ecf20Sopenharmony_ci			__func__, rc);
2828c2ecf20Sopenharmony_ci		goto out_chip;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ciout_chip:
2888c2ecf20Sopenharmony_ci	put_device(&pvt_data->chip->dev);
2898c2ecf20Sopenharmony_ciout_chip_alloc:
2908c2ecf20Sopenharmony_ci	tee_shm_free(pvt_data->shm);
2918c2ecf20Sopenharmony_ciout_shm_alloc:
2928c2ecf20Sopenharmony_ci	tee_client_close_session(pvt_data->ctx, pvt_data->session);
2938c2ecf20Sopenharmony_ciout_tee_session:
2948c2ecf20Sopenharmony_ci	tee_client_close_context(pvt_data->ctx);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return rc;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic int ftpm_plat_tee_probe(struct platform_device *pdev)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return ftpm_tee_probe(dev);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/**
3078c2ecf20Sopenharmony_ci * ftpm_tee_remove() - remove the TPM device
3088c2ecf20Sopenharmony_ci * @pdev: the platform_device description.
3098c2ecf20Sopenharmony_ci *
3108c2ecf20Sopenharmony_ci * Return:
3118c2ecf20Sopenharmony_ci *	0 always.
3128c2ecf20Sopenharmony_ci */
3138c2ecf20Sopenharmony_cistatic int ftpm_tee_remove(struct device *dev)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct ftpm_tee_private *pvt_data = dev_get_drvdata(dev);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* Release the chip */
3188c2ecf20Sopenharmony_ci	tpm_chip_unregister(pvt_data->chip);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* frees chip */
3218c2ecf20Sopenharmony_ci	put_device(&pvt_data->chip->dev);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	/* Free the shared memory pool */
3248c2ecf20Sopenharmony_ci	tee_shm_free(pvt_data->shm);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/* close the existing session with fTPM TA*/
3278c2ecf20Sopenharmony_ci	tee_client_close_session(pvt_data->ctx, pvt_data->session);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* close the context with TEE driver */
3308c2ecf20Sopenharmony_ci	tee_client_close_context(pvt_data->ctx);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* memory allocated with devm_kzalloc() is freed automatically */
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return 0;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic int ftpm_plat_tee_remove(struct platform_device *pdev)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return ftpm_tee_remove(dev);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/**
3458c2ecf20Sopenharmony_ci * ftpm_tee_shutdown() - shutdown the TPM device
3468c2ecf20Sopenharmony_ci * @pdev: the platform_device description.
3478c2ecf20Sopenharmony_ci */
3488c2ecf20Sopenharmony_cistatic void ftpm_plat_tee_shutdown(struct platform_device *pdev)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	tee_shm_free(pvt_data->shm);
3538c2ecf20Sopenharmony_ci	tee_client_close_session(pvt_data->ctx, pvt_data->session);
3548c2ecf20Sopenharmony_ci	tee_client_close_context(pvt_data->ctx);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic const struct of_device_id of_ftpm_tee_ids[] = {
3588c2ecf20Sopenharmony_ci	{ .compatible = "microsoft,ftpm" },
3598c2ecf20Sopenharmony_ci	{ }
3608c2ecf20Sopenharmony_ci};
3618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_ftpm_tee_ids);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic struct platform_driver ftpm_tee_plat_driver = {
3648c2ecf20Sopenharmony_ci	.driver = {
3658c2ecf20Sopenharmony_ci		.name = "ftpm-tee",
3668c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(of_ftpm_tee_ids),
3678c2ecf20Sopenharmony_ci	},
3688c2ecf20Sopenharmony_ci	.shutdown = ftpm_plat_tee_shutdown,
3698c2ecf20Sopenharmony_ci	.probe = ftpm_plat_tee_probe,
3708c2ecf20Sopenharmony_ci	.remove = ftpm_plat_tee_remove,
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/* UUID of the fTPM TA */
3748c2ecf20Sopenharmony_cistatic const struct tee_client_device_id optee_ftpm_id_table[] = {
3758c2ecf20Sopenharmony_ci	{UUID_INIT(0xbc50d971, 0xd4c9, 0x42c4,
3768c2ecf20Sopenharmony_ci		   0x82, 0xcb, 0x34, 0x3f, 0xb7, 0xf3, 0x78, 0x96)},
3778c2ecf20Sopenharmony_ci	{}
3788c2ecf20Sopenharmony_ci};
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(tee, optee_ftpm_id_table);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic struct tee_client_driver ftpm_tee_driver = {
3838c2ecf20Sopenharmony_ci	.id_table	= optee_ftpm_id_table,
3848c2ecf20Sopenharmony_ci	.driver		= {
3858c2ecf20Sopenharmony_ci		.name		= "optee-ftpm",
3868c2ecf20Sopenharmony_ci		.bus		= &tee_bus_type,
3878c2ecf20Sopenharmony_ci		.probe		= ftpm_tee_probe,
3888c2ecf20Sopenharmony_ci		.remove		= ftpm_tee_remove,
3898c2ecf20Sopenharmony_ci	},
3908c2ecf20Sopenharmony_ci};
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int __init ftpm_mod_init(void)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	int rc;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	rc = platform_driver_register(&ftpm_tee_plat_driver);
3978c2ecf20Sopenharmony_ci	if (rc)
3988c2ecf20Sopenharmony_ci		return rc;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	rc = driver_register(&ftpm_tee_driver.driver);
4018c2ecf20Sopenharmony_ci	if (rc) {
4028c2ecf20Sopenharmony_ci		platform_driver_unregister(&ftpm_tee_plat_driver);
4038c2ecf20Sopenharmony_ci		return rc;
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	return 0;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic void __exit ftpm_mod_exit(void)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	platform_driver_unregister(&ftpm_tee_plat_driver);
4128c2ecf20Sopenharmony_ci	driver_unregister(&ftpm_tee_driver.driver);
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cimodule_init(ftpm_mod_init);
4168c2ecf20Sopenharmony_cimodule_exit(ftpm_mod_exit);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Thirupathaiah Annapureddy <thiruan@microsoft.com>");
4198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE");
4208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
421