18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AMD Trusted Execution Environment (TEE) interface
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
68c2ecf20Sopenharmony_ci * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/types.h>
128c2ecf20Sopenharmony_ci#include <linux/mutex.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/gfp.h>
168c2ecf20Sopenharmony_ci#include <linux/psp-sev.h>
178c2ecf20Sopenharmony_ci#include <linux/psp-tee.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "psp-dev.h"
208c2ecf20Sopenharmony_ci#include "tee-dev.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic bool psp_dead;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
278c2ecf20Sopenharmony_ci	void *start_addr;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	if (!ring_size)
308c2ecf20Sopenharmony_ci		return -EINVAL;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	/* We need actual physical address instead of DMA address, since
338c2ecf20Sopenharmony_ci	 * Trusted OS running on AMD Secure Processor will map this region
348c2ecf20Sopenharmony_ci	 */
358c2ecf20Sopenharmony_ci	start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size));
368c2ecf20Sopenharmony_ci	if (!start_addr)
378c2ecf20Sopenharmony_ci		return -ENOMEM;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	memset(start_addr, 0x0, ring_size);
408c2ecf20Sopenharmony_ci	rb_mgr->ring_start = start_addr;
418c2ecf20Sopenharmony_ci	rb_mgr->ring_size = ring_size;
428c2ecf20Sopenharmony_ci	rb_mgr->ring_pa = __psp_pa(start_addr);
438c2ecf20Sopenharmony_ci	mutex_init(&rb_mgr->mutex);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	return 0;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void tee_free_ring(struct psp_tee_device *tee)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (!rb_mgr->ring_start)
538c2ecf20Sopenharmony_ci		return;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	free_pages((unsigned long)rb_mgr->ring_start,
568c2ecf20Sopenharmony_ci		   get_order(rb_mgr->ring_size));
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	rb_mgr->ring_start = NULL;
598c2ecf20Sopenharmony_ci	rb_mgr->ring_size = 0;
608c2ecf20Sopenharmony_ci	rb_mgr->ring_pa = 0;
618c2ecf20Sopenharmony_ci	mutex_destroy(&rb_mgr->mutex);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
658c2ecf20Sopenharmony_ci			     unsigned int *reg)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	/* ~10ms sleep per loop => nloop = timeout * 100 */
688c2ecf20Sopenharmony_ci	int nloop = timeout * 100;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	while (--nloop) {
718c2ecf20Sopenharmony_ci		*reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg);
728c2ecf20Sopenharmony_ci		if (*reg & PSP_CMDRESP_RESP)
738c2ecf20Sopenharmony_ci			return 0;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		usleep_range(10000, 10100);
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	dev_err(tee->dev, "tee: command timed out, disabling PSP\n");
798c2ecf20Sopenharmony_ci	psp_dead = true;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic
858c2ecf20Sopenharmony_cistruct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct tee_init_ring_cmd *cmd;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
908c2ecf20Sopenharmony_ci	if (!cmd)
918c2ecf20Sopenharmony_ci		return NULL;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa);
948c2ecf20Sopenharmony_ci	cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa);
958c2ecf20Sopenharmony_ci	cmd->size = tee->rb_mgr.ring_size;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n",
988c2ecf20Sopenharmony_ci		cmd->hi_addr, cmd->low_addr, cmd->size);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return cmd;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	kfree(cmd);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int tee_init_ring(struct psp_tee_device *tee)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
1118c2ecf20Sopenharmony_ci	struct tee_init_ring_cmd *cmd;
1128c2ecf20Sopenharmony_ci	phys_addr_t cmd_buffer;
1138c2ecf20Sopenharmony_ci	unsigned int reg;
1148c2ecf20Sopenharmony_ci	int ret;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	ret = tee_alloc_ring(tee, ring_size);
1198c2ecf20Sopenharmony_ci	if (ret) {
1208c2ecf20Sopenharmony_ci		dev_err(tee->dev, "tee: ring allocation failed %d\n", ret);
1218c2ecf20Sopenharmony_ci		return ret;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	tee->rb_mgr.wptr = 0;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	cmd = tee_alloc_cmd_buffer(tee);
1278c2ecf20Sopenharmony_ci	if (!cmd) {
1288c2ecf20Sopenharmony_ci		tee_free_ring(tee);
1298c2ecf20Sopenharmony_ci		return -ENOMEM;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	cmd_buffer = __psp_pa((void *)cmd);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* Send command buffer details to Trusted OS by writing to
1358c2ecf20Sopenharmony_ci	 * CPU-PSP message registers
1368c2ecf20Sopenharmony_ci	 */
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	iowrite32(lower_32_bits(cmd_buffer),
1398c2ecf20Sopenharmony_ci		  tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg);
1408c2ecf20Sopenharmony_ci	iowrite32(upper_32_bits(cmd_buffer),
1418c2ecf20Sopenharmony_ci		  tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg);
1428c2ecf20Sopenharmony_ci	iowrite32(TEE_RING_INIT_CMD,
1438c2ecf20Sopenharmony_ci		  tee->io_regs + tee->vdata->cmdresp_reg);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
1468c2ecf20Sopenharmony_ci	if (ret) {
1478c2ecf20Sopenharmony_ci		dev_err(tee->dev, "tee: ring init command timed out\n");
1488c2ecf20Sopenharmony_ci		tee_free_ring(tee);
1498c2ecf20Sopenharmony_ci		goto free_buf;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (reg & PSP_CMDRESP_ERR_MASK) {
1538c2ecf20Sopenharmony_ci		dev_err(tee->dev, "tee: ring init command failed (%#010x)\n",
1548c2ecf20Sopenharmony_ci			reg & PSP_CMDRESP_ERR_MASK);
1558c2ecf20Sopenharmony_ci		tee_free_ring(tee);
1568c2ecf20Sopenharmony_ci		ret = -EIO;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cifree_buf:
1608c2ecf20Sopenharmony_ci	tee_free_cmd_buffer(cmd);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	return ret;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic void tee_destroy_ring(struct psp_tee_device *tee)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	unsigned int reg;
1688c2ecf20Sopenharmony_ci	int ret;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (!tee->rb_mgr.ring_start)
1718c2ecf20Sopenharmony_ci		return;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (psp_dead)
1748c2ecf20Sopenharmony_ci		goto free_ring;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	iowrite32(TEE_RING_DESTROY_CMD,
1778c2ecf20Sopenharmony_ci		  tee->io_regs + tee->vdata->cmdresp_reg);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
1808c2ecf20Sopenharmony_ci	if (ret) {
1818c2ecf20Sopenharmony_ci		dev_err(tee->dev, "tee: ring destroy command timed out\n");
1828c2ecf20Sopenharmony_ci	} else if (reg & PSP_CMDRESP_ERR_MASK) {
1838c2ecf20Sopenharmony_ci		dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n",
1848c2ecf20Sopenharmony_ci			reg & PSP_CMDRESP_ERR_MASK);
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cifree_ring:
1888c2ecf20Sopenharmony_ci	tee_free_ring(tee);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ciint tee_dev_init(struct psp_device *psp)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct device *dev = psp->dev;
1948c2ecf20Sopenharmony_ci	struct psp_tee_device *tee;
1958c2ecf20Sopenharmony_ci	int ret;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	ret = -ENOMEM;
1988c2ecf20Sopenharmony_ci	tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL);
1998c2ecf20Sopenharmony_ci	if (!tee)
2008c2ecf20Sopenharmony_ci		goto e_err;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	psp->tee_data = tee;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	tee->dev = dev;
2058c2ecf20Sopenharmony_ci	tee->psp = psp;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	tee->io_regs = psp->io_regs;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	tee->vdata = (struct tee_vdata *)psp->vdata->tee;
2108c2ecf20Sopenharmony_ci	if (!tee->vdata) {
2118c2ecf20Sopenharmony_ci		ret = -ENODEV;
2128c2ecf20Sopenharmony_ci		dev_err(dev, "tee: missing driver data\n");
2138c2ecf20Sopenharmony_ci		goto e_err;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	ret = tee_init_ring(tee);
2178c2ecf20Sopenharmony_ci	if (ret) {
2188c2ecf20Sopenharmony_ci		dev_err(dev, "tee: failed to init ring buffer\n");
2198c2ecf20Sopenharmony_ci		goto e_err;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	dev_notice(dev, "tee enabled\n");
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return 0;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cie_err:
2278c2ecf20Sopenharmony_ci	psp->tee_data = NULL;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	dev_notice(dev, "tee initialization failed\n");
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return ret;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_civoid tee_dev_destroy(struct psp_device *psp)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct psp_tee_device *tee = psp->tee_data;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (!tee)
2398c2ecf20Sopenharmony_ci		return;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	tee_destroy_ring(tee);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,
2458c2ecf20Sopenharmony_ci			  void *buf, size_t len, struct tee_ring_cmd **resp)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct tee_ring_cmd *cmd;
2488c2ecf20Sopenharmony_ci	int nloop = 1000, ret = 0;
2498c2ecf20Sopenharmony_ci	u32 rptr;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	*resp = NULL;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	mutex_lock(&tee->rb_mgr.mutex);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/* Loop until empty entry found in ring buffer */
2568c2ecf20Sopenharmony_ci	do {
2578c2ecf20Sopenharmony_ci		/* Get pointer to ring buffer command entry */
2588c2ecf20Sopenharmony_ci		cmd = (struct tee_ring_cmd *)
2598c2ecf20Sopenharmony_ci			(tee->rb_mgr.ring_start + tee->rb_mgr.wptr);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		/* Check if ring buffer is full or command entry is waiting
2648c2ecf20Sopenharmony_ci		 * for response from TEE
2658c2ecf20Sopenharmony_ci		 */
2668c2ecf20Sopenharmony_ci		if (!(tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr ||
2678c2ecf20Sopenharmony_ci		      cmd->flag == CMD_WAITING_FOR_RESPONSE))
2688c2ecf20Sopenharmony_ci			break;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		dev_dbg(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
2718c2ecf20Sopenharmony_ci			rptr, tee->rb_mgr.wptr);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		/* Wait if ring buffer is full or TEE is processing data */
2748c2ecf20Sopenharmony_ci		mutex_unlock(&tee->rb_mgr.mutex);
2758c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(msecs_to_jiffies(10));
2768c2ecf20Sopenharmony_ci		mutex_lock(&tee->rb_mgr.mutex);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	} while (--nloop);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	if (!nloop &&
2818c2ecf20Sopenharmony_ci	    (tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr ||
2828c2ecf20Sopenharmony_ci	     cmd->flag == CMD_WAITING_FOR_RESPONSE)) {
2838c2ecf20Sopenharmony_ci		dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u response flag %u\n",
2848c2ecf20Sopenharmony_ci			rptr, tee->rb_mgr.wptr, cmd->flag);
2858c2ecf20Sopenharmony_ci		ret = -EBUSY;
2868c2ecf20Sopenharmony_ci		goto unlock;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* Do not submit command if PSP got disabled while processing any
2908c2ecf20Sopenharmony_ci	 * command in another thread
2918c2ecf20Sopenharmony_ci	 */
2928c2ecf20Sopenharmony_ci	if (psp_dead) {
2938c2ecf20Sopenharmony_ci		ret = -EBUSY;
2948c2ecf20Sopenharmony_ci		goto unlock;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/* Write command data into ring buffer */
2988c2ecf20Sopenharmony_ci	cmd->cmd_id = cmd_id;
2998c2ecf20Sopenharmony_ci	cmd->cmd_state = TEE_CMD_STATE_INIT;
3008c2ecf20Sopenharmony_ci	memset(&cmd->buf[0], 0, sizeof(cmd->buf));
3018c2ecf20Sopenharmony_ci	memcpy(&cmd->buf[0], buf, len);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* Indicate driver is waiting for response */
3048c2ecf20Sopenharmony_ci	cmd->flag = CMD_WAITING_FOR_RESPONSE;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* Update local copy of write pointer */
3078c2ecf20Sopenharmony_ci	tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd);
3088c2ecf20Sopenharmony_ci	if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size)
3098c2ecf20Sopenharmony_ci		tee->rb_mgr.wptr = 0;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/* Trigger interrupt to Trusted OS */
3128c2ecf20Sopenharmony_ci	iowrite32(tee->rb_mgr.wptr, tee->io_regs + tee->vdata->ring_wptr_reg);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* The response is provided by Trusted OS in same
3158c2ecf20Sopenharmony_ci	 * location as submitted data entry within ring buffer.
3168c2ecf20Sopenharmony_ci	 */
3178c2ecf20Sopenharmony_ci	*resp = cmd;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ciunlock:
3208c2ecf20Sopenharmony_ci	mutex_unlock(&tee->rb_mgr.mutex);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return ret;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int tee_wait_cmd_completion(struct psp_tee_device *tee,
3268c2ecf20Sopenharmony_ci				   struct tee_ring_cmd *resp,
3278c2ecf20Sopenharmony_ci				   unsigned int timeout)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	/* ~5ms sleep per loop => nloop = timeout * 200 */
3308c2ecf20Sopenharmony_ci	int nloop = timeout * 200;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	while (--nloop) {
3338c2ecf20Sopenharmony_ci		if (resp->cmd_state == TEE_CMD_STATE_COMPLETED)
3348c2ecf20Sopenharmony_ci			return 0;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		usleep_range(5000, 5100);
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n",
3408c2ecf20Sopenharmony_ci		resp->cmd_id);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	psp_dead = true;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ciint psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
3488c2ecf20Sopenharmony_ci			u32 *status)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	struct psp_device *psp = psp_get_master_device();
3518c2ecf20Sopenharmony_ci	struct psp_tee_device *tee;
3528c2ecf20Sopenharmony_ci	struct tee_ring_cmd *resp;
3538c2ecf20Sopenharmony_ci	int ret;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (!buf || !status || !len || len > sizeof(resp->buf))
3568c2ecf20Sopenharmony_ci		return -EINVAL;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	*status = 0;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (!psp || !psp->tee_data)
3618c2ecf20Sopenharmony_ci		return -ENODEV;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (psp_dead)
3648c2ecf20Sopenharmony_ci		return -EBUSY;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	tee = psp->tee_data;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	ret = tee_submit_cmd(tee, cmd_id, buf, len, &resp);
3698c2ecf20Sopenharmony_ci	if (ret)
3708c2ecf20Sopenharmony_ci		return ret;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT);
3738c2ecf20Sopenharmony_ci	if (ret) {
3748c2ecf20Sopenharmony_ci		resp->flag = CMD_RESPONSE_TIMEDOUT;
3758c2ecf20Sopenharmony_ci		return ret;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	memcpy(buf, &resp->buf[0], len);
3798c2ecf20Sopenharmony_ci	*status = resp->status;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	resp->flag = CMD_RESPONSE_COPIED;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	return 0;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(psp_tee_process_cmd);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ciint psp_check_tee_status(void)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct psp_device *psp = psp_get_master_device();
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if (!psp || !psp->tee_data)
3928c2ecf20Sopenharmony_ci		return -ENODEV;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(psp_check_tee_status);
397