133960accSRijo Thomas // SPDX-License-Identifier: MIT
233960accSRijo Thomas /*
333960accSRijo Thomas * AMD Trusted Execution Environment (TEE) interface
433960accSRijo Thomas *
533960accSRijo Thomas * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
633960accSRijo Thomas * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
733960accSRijo Thomas *
84a5eed17SRijo Thomas * Copyright (C) 2019,2021 Advanced Micro Devices, Inc.
933960accSRijo Thomas */
1033960accSRijo Thomas
11*1c5c1dafSMario Limonciello #include <linux/bitfield.h>
1233960accSRijo Thomas #include <linux/types.h>
1333960accSRijo Thomas #include <linux/mutex.h>
1433960accSRijo Thomas #include <linux/delay.h>
1533960accSRijo Thomas #include <linux/slab.h>
1633960accSRijo Thomas #include <linux/gfp.h>
17ae7d45fbSMario Limonciello #include <linux/psp.h>
18632b0b53SRijo Thomas #include <linux/psp-tee.h>
1933960accSRijo Thomas
2033960accSRijo Thomas #include "psp-dev.h"
2133960accSRijo Thomas #include "tee-dev.h"
2233960accSRijo Thomas
2333960accSRijo Thomas static bool psp_dead;
2433960accSRijo Thomas
tee_alloc_ring(struct psp_tee_device * tee,int ring_size)2533960accSRijo Thomas static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
2633960accSRijo Thomas {
2733960accSRijo Thomas struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
2833960accSRijo Thomas void *start_addr;
2933960accSRijo Thomas
3033960accSRijo Thomas if (!ring_size)
3133960accSRijo Thomas return -EINVAL;
3233960accSRijo Thomas
3333960accSRijo Thomas /* We need actual physical address instead of DMA address, since
3433960accSRijo Thomas * Trusted OS running on AMD Secure Processor will map this region
3533960accSRijo Thomas */
3633960accSRijo Thomas start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size));
3733960accSRijo Thomas if (!start_addr)
3833960accSRijo Thomas return -ENOMEM;
3933960accSRijo Thomas
4000aa6e65SRijo Thomas memset(start_addr, 0x0, ring_size);
4133960accSRijo Thomas rb_mgr->ring_start = start_addr;
4233960accSRijo Thomas rb_mgr->ring_size = ring_size;
4333960accSRijo Thomas rb_mgr->ring_pa = __psp_pa(start_addr);
44632b0b53SRijo Thomas mutex_init(&rb_mgr->mutex);
4533960accSRijo Thomas
4633960accSRijo Thomas return 0;
4733960accSRijo Thomas }
4833960accSRijo Thomas
tee_free_ring(struct psp_tee_device * tee)4933960accSRijo Thomas static void tee_free_ring(struct psp_tee_device *tee)
5033960accSRijo Thomas {
5133960accSRijo Thomas struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
5233960accSRijo Thomas
5333960accSRijo Thomas if (!rb_mgr->ring_start)
5433960accSRijo Thomas return;
5533960accSRijo Thomas
5633960accSRijo Thomas free_pages((unsigned long)rb_mgr->ring_start,
5733960accSRijo Thomas get_order(rb_mgr->ring_size));
5833960accSRijo Thomas
5933960accSRijo Thomas rb_mgr->ring_start = NULL;
6033960accSRijo Thomas rb_mgr->ring_size = 0;
6133960accSRijo Thomas rb_mgr->ring_pa = 0;
62632b0b53SRijo Thomas mutex_destroy(&rb_mgr->mutex);
6333960accSRijo Thomas }
6433960accSRijo Thomas
tee_wait_cmd_poll(struct psp_tee_device * tee,unsigned int timeout,unsigned int * reg)6533960accSRijo Thomas static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
6633960accSRijo Thomas unsigned int *reg)
6733960accSRijo Thomas {
6833960accSRijo Thomas /* ~10ms sleep per loop => nloop = timeout * 100 */
6933960accSRijo Thomas int nloop = timeout * 100;
7033960accSRijo Thomas
7133960accSRijo Thomas while (--nloop) {
7233960accSRijo Thomas *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg);
73*1c5c1dafSMario Limonciello if (FIELD_GET(PSP_CMDRESP_RESP, *reg))
7433960accSRijo Thomas return 0;
7533960accSRijo Thomas
7633960accSRijo Thomas usleep_range(10000, 10100);
7733960accSRijo Thomas }
7833960accSRijo Thomas
7933960accSRijo Thomas dev_err(tee->dev, "tee: command timed out, disabling PSP\n");
8033960accSRijo Thomas psp_dead = true;
8133960accSRijo Thomas
8233960accSRijo Thomas return -ETIMEDOUT;
8333960accSRijo Thomas }
8433960accSRijo Thomas
8533960accSRijo Thomas static
tee_alloc_cmd_buffer(struct psp_tee_device * tee)8633960accSRijo Thomas struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
8733960accSRijo Thomas {
8833960accSRijo Thomas struct tee_init_ring_cmd *cmd;
8933960accSRijo Thomas
9033960accSRijo Thomas cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
9133960accSRijo Thomas if (!cmd)
9233960accSRijo Thomas return NULL;
9333960accSRijo Thomas
9433960accSRijo Thomas cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa);
9533960accSRijo Thomas cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa);
9633960accSRijo Thomas cmd->size = tee->rb_mgr.ring_size;
9733960accSRijo Thomas
9833960accSRijo Thomas dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n",
9933960accSRijo Thomas cmd->hi_addr, cmd->low_addr, cmd->size);
10033960accSRijo Thomas
10133960accSRijo Thomas return cmd;
10233960accSRijo Thomas }
10333960accSRijo Thomas
tee_free_cmd_buffer(struct tee_init_ring_cmd * cmd)10433960accSRijo Thomas static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
10533960accSRijo Thomas {
10633960accSRijo Thomas kfree(cmd);
10733960accSRijo Thomas }
10833960accSRijo Thomas
tee_init_ring(struct psp_tee_device * tee)10933960accSRijo Thomas static int tee_init_ring(struct psp_tee_device *tee)
11033960accSRijo Thomas {
11133960accSRijo Thomas int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
11233960accSRijo Thomas struct tee_init_ring_cmd *cmd;
11333960accSRijo Thomas phys_addr_t cmd_buffer;
11433960accSRijo Thomas unsigned int reg;
11533960accSRijo Thomas int ret;
11633960accSRijo Thomas
11733960accSRijo Thomas BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024);
11833960accSRijo Thomas
11933960accSRijo Thomas ret = tee_alloc_ring(tee, ring_size);
12033960accSRijo Thomas if (ret) {
12133960accSRijo Thomas dev_err(tee->dev, "tee: ring allocation failed %d\n", ret);
12233960accSRijo Thomas return ret;
12333960accSRijo Thomas }
12433960accSRijo Thomas
12533960accSRijo Thomas tee->rb_mgr.wptr = 0;
12633960accSRijo Thomas
12733960accSRijo Thomas cmd = tee_alloc_cmd_buffer(tee);
12833960accSRijo Thomas if (!cmd) {
12933960accSRijo Thomas tee_free_ring(tee);
13033960accSRijo Thomas return -ENOMEM;
13133960accSRijo Thomas }
13233960accSRijo Thomas
13333960accSRijo Thomas cmd_buffer = __psp_pa((void *)cmd);
13433960accSRijo Thomas
13533960accSRijo Thomas /* Send command buffer details to Trusted OS by writing to
13633960accSRijo Thomas * CPU-PSP message registers
13733960accSRijo Thomas */
13833960accSRijo Thomas
13933960accSRijo Thomas iowrite32(lower_32_bits(cmd_buffer),
14033960accSRijo Thomas tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg);
14133960accSRijo Thomas iowrite32(upper_32_bits(cmd_buffer),
14233960accSRijo Thomas tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg);
14333960accSRijo Thomas iowrite32(TEE_RING_INIT_CMD,
14433960accSRijo Thomas tee->io_regs + tee->vdata->cmdresp_reg);
14533960accSRijo Thomas
14633960accSRijo Thomas ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®);
14733960accSRijo Thomas if (ret) {
14833960accSRijo Thomas dev_err(tee->dev, "tee: ring init command timed out\n");
14933960accSRijo Thomas tee_free_ring(tee);
15033960accSRijo Thomas goto free_buf;
15133960accSRijo Thomas }
15233960accSRijo Thomas
153*1c5c1dafSMario Limonciello if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
154*1c5c1dafSMario Limonciello dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n",
155*1c5c1dafSMario Limonciello FIELD_GET(PSP_CMDRESP_STS, reg));
15633960accSRijo Thomas tee_free_ring(tee);
15733960accSRijo Thomas ret = -EIO;
15833960accSRijo Thomas }
15933960accSRijo Thomas
16033960accSRijo Thomas free_buf:
16133960accSRijo Thomas tee_free_cmd_buffer(cmd);
16233960accSRijo Thomas
16333960accSRijo Thomas return ret;
16433960accSRijo Thomas }
16533960accSRijo Thomas
tee_destroy_ring(struct psp_tee_device * tee)16633960accSRijo Thomas static void tee_destroy_ring(struct psp_tee_device *tee)
16733960accSRijo Thomas {
16833960accSRijo Thomas unsigned int reg;
16933960accSRijo Thomas int ret;
17033960accSRijo Thomas
17133960accSRijo Thomas if (!tee->rb_mgr.ring_start)
17233960accSRijo Thomas return;
17333960accSRijo Thomas
17433960accSRijo Thomas if (psp_dead)
17533960accSRijo Thomas goto free_ring;
17633960accSRijo Thomas
17733960accSRijo Thomas iowrite32(TEE_RING_DESTROY_CMD,
17833960accSRijo Thomas tee->io_regs + tee->vdata->cmdresp_reg);
17933960accSRijo Thomas
18033960accSRijo Thomas ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®);
18133960accSRijo Thomas if (ret) {
18233960accSRijo Thomas dev_err(tee->dev, "tee: ring destroy command timed out\n");
183*1c5c1dafSMario Limonciello } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
184*1c5c1dafSMario Limonciello dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n",
185*1c5c1dafSMario Limonciello FIELD_GET(PSP_CMDRESP_STS, reg));
18633960accSRijo Thomas }
18733960accSRijo Thomas
18833960accSRijo Thomas free_ring:
18933960accSRijo Thomas tee_free_ring(tee);
19033960accSRijo Thomas }
19133960accSRijo Thomas
tee_dev_init(struct psp_device * psp)19233960accSRijo Thomas int tee_dev_init(struct psp_device *psp)
19333960accSRijo Thomas {
19433960accSRijo Thomas struct device *dev = psp->dev;
19533960accSRijo Thomas struct psp_tee_device *tee;
19633960accSRijo Thomas int ret;
19733960accSRijo Thomas
19833960accSRijo Thomas ret = -ENOMEM;
19933960accSRijo Thomas tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL);
20033960accSRijo Thomas if (!tee)
20133960accSRijo Thomas goto e_err;
20233960accSRijo Thomas
20333960accSRijo Thomas psp->tee_data = tee;
20433960accSRijo Thomas
20533960accSRijo Thomas tee->dev = dev;
20633960accSRijo Thomas tee->psp = psp;
20733960accSRijo Thomas
20833960accSRijo Thomas tee->io_regs = psp->io_regs;
20933960accSRijo Thomas
21033960accSRijo Thomas tee->vdata = (struct tee_vdata *)psp->vdata->tee;
21133960accSRijo Thomas if (!tee->vdata) {
21233960accSRijo Thomas ret = -ENODEV;
21333960accSRijo Thomas dev_err(dev, "tee: missing driver data\n");
21433960accSRijo Thomas goto e_err;
21533960accSRijo Thomas }
21633960accSRijo Thomas
21733960accSRijo Thomas ret = tee_init_ring(tee);
21833960accSRijo Thomas if (ret) {
21933960accSRijo Thomas dev_err(dev, "tee: failed to init ring buffer\n");
22033960accSRijo Thomas goto e_err;
22133960accSRijo Thomas }
22233960accSRijo Thomas
22333960accSRijo Thomas dev_notice(dev, "tee enabled\n");
22433960accSRijo Thomas
22533960accSRijo Thomas return 0;
22633960accSRijo Thomas
22733960accSRijo Thomas e_err:
22833960accSRijo Thomas psp->tee_data = NULL;
22933960accSRijo Thomas
23033960accSRijo Thomas dev_notice(dev, "tee initialization failed\n");
23133960accSRijo Thomas
23233960accSRijo Thomas return ret;
23333960accSRijo Thomas }
23433960accSRijo Thomas
tee_dev_destroy(struct psp_device * psp)23533960accSRijo Thomas void tee_dev_destroy(struct psp_device *psp)
23633960accSRijo Thomas {
23733960accSRijo Thomas struct psp_tee_device *tee = psp->tee_data;
23833960accSRijo Thomas
23933960accSRijo Thomas if (!tee)
24033960accSRijo Thomas return;
24133960accSRijo Thomas
24233960accSRijo Thomas tee_destroy_ring(tee);
24333960accSRijo Thomas }
244632b0b53SRijo Thomas
tee_submit_cmd(struct psp_tee_device * tee,enum tee_cmd_id cmd_id,void * buf,size_t len,struct tee_ring_cmd ** resp)245632b0b53SRijo Thomas static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,
246632b0b53SRijo Thomas void *buf, size_t len, struct tee_ring_cmd **resp)
247632b0b53SRijo Thomas {
248632b0b53SRijo Thomas struct tee_ring_cmd *cmd;
249632b0b53SRijo Thomas int nloop = 1000, ret = 0;
25000aa6e65SRijo Thomas u32 rptr;
251632b0b53SRijo Thomas
252632b0b53SRijo Thomas *resp = NULL;
253632b0b53SRijo Thomas
254632b0b53SRijo Thomas mutex_lock(&tee->rb_mgr.mutex);
255632b0b53SRijo Thomas
25600aa6e65SRijo Thomas /* Loop until empty entry found in ring buffer */
257632b0b53SRijo Thomas do {
25800aa6e65SRijo Thomas /* Get pointer to ring buffer command entry */
25900aa6e65SRijo Thomas cmd = (struct tee_ring_cmd *)
26000aa6e65SRijo Thomas (tee->rb_mgr.ring_start + tee->rb_mgr.wptr);
26100aa6e65SRijo Thomas
262632b0b53SRijo Thomas rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg);
263632b0b53SRijo Thomas
26400aa6e65SRijo Thomas /* Check if ring buffer is full or command entry is waiting
26500aa6e65SRijo Thomas * for response from TEE
26600aa6e65SRijo Thomas */
26700aa6e65SRijo Thomas if (!(tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr ||
26800aa6e65SRijo Thomas cmd->flag == CMD_WAITING_FOR_RESPONSE))
269632b0b53SRijo Thomas break;
270632b0b53SRijo Thomas
27100aa6e65SRijo Thomas dev_dbg(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
27200aa6e65SRijo Thomas rptr, tee->rb_mgr.wptr);
273632b0b53SRijo Thomas
27400aa6e65SRijo Thomas /* Wait if ring buffer is full or TEE is processing data */
275632b0b53SRijo Thomas mutex_unlock(&tee->rb_mgr.mutex);
276632b0b53SRijo Thomas schedule_timeout_interruptible(msecs_to_jiffies(10));
277632b0b53SRijo Thomas mutex_lock(&tee->rb_mgr.mutex);
278632b0b53SRijo Thomas
279632b0b53SRijo Thomas } while (--nloop);
280632b0b53SRijo Thomas
28100aa6e65SRijo Thomas if (!nloop &&
28200aa6e65SRijo Thomas (tee->rb_mgr.wptr + sizeof(struct tee_ring_cmd) == rptr ||
28300aa6e65SRijo Thomas cmd->flag == CMD_WAITING_FOR_RESPONSE)) {
28400aa6e65SRijo Thomas dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u response flag %u\n",
28500aa6e65SRijo Thomas rptr, tee->rb_mgr.wptr, cmd->flag);
286632b0b53SRijo Thomas ret = -EBUSY;
287632b0b53SRijo Thomas goto unlock;
288632b0b53SRijo Thomas }
289632b0b53SRijo Thomas
29000aa6e65SRijo Thomas /* Do not submit command if PSP got disabled while processing any
29100aa6e65SRijo Thomas * command in another thread
29200aa6e65SRijo Thomas */
29300aa6e65SRijo Thomas if (psp_dead) {
29400aa6e65SRijo Thomas ret = -EBUSY;
29500aa6e65SRijo Thomas goto unlock;
29600aa6e65SRijo Thomas }
297632b0b53SRijo Thomas
298632b0b53SRijo Thomas /* Write command data into ring buffer */
299632b0b53SRijo Thomas cmd->cmd_id = cmd_id;
300632b0b53SRijo Thomas cmd->cmd_state = TEE_CMD_STATE_INIT;
301632b0b53SRijo Thomas memset(&cmd->buf[0], 0, sizeof(cmd->buf));
302632b0b53SRijo Thomas memcpy(&cmd->buf[0], buf, len);
303632b0b53SRijo Thomas
30400aa6e65SRijo Thomas /* Indicate driver is waiting for response */
30500aa6e65SRijo Thomas cmd->flag = CMD_WAITING_FOR_RESPONSE;
30600aa6e65SRijo Thomas
307632b0b53SRijo Thomas /* Update local copy of write pointer */
308632b0b53SRijo Thomas tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd);
309632b0b53SRijo Thomas if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size)
310632b0b53SRijo Thomas tee->rb_mgr.wptr = 0;
311632b0b53SRijo Thomas
312632b0b53SRijo Thomas /* Trigger interrupt to Trusted OS */
313632b0b53SRijo Thomas iowrite32(tee->rb_mgr.wptr, tee->io_regs + tee->vdata->ring_wptr_reg);
314632b0b53SRijo Thomas
315632b0b53SRijo Thomas /* The response is provided by Trusted OS in same
316632b0b53SRijo Thomas * location as submitted data entry within ring buffer.
317632b0b53SRijo Thomas */
318632b0b53SRijo Thomas *resp = cmd;
319632b0b53SRijo Thomas
320632b0b53SRijo Thomas unlock:
321632b0b53SRijo Thomas mutex_unlock(&tee->rb_mgr.mutex);
322632b0b53SRijo Thomas
323632b0b53SRijo Thomas return ret;
324632b0b53SRijo Thomas }
325632b0b53SRijo Thomas
tee_wait_cmd_completion(struct psp_tee_device * tee,struct tee_ring_cmd * resp,unsigned int timeout)326632b0b53SRijo Thomas static int tee_wait_cmd_completion(struct psp_tee_device *tee,
327632b0b53SRijo Thomas struct tee_ring_cmd *resp,
328632b0b53SRijo Thomas unsigned int timeout)
329632b0b53SRijo Thomas {
3304a5eed17SRijo Thomas /* ~1ms sleep per loop => nloop = timeout * 1000 */
3314a5eed17SRijo Thomas int nloop = timeout * 1000;
332632b0b53SRijo Thomas
333632b0b53SRijo Thomas while (--nloop) {
334632b0b53SRijo Thomas if (resp->cmd_state == TEE_CMD_STATE_COMPLETED)
335632b0b53SRijo Thomas return 0;
336632b0b53SRijo Thomas
3374a5eed17SRijo Thomas usleep_range(1000, 1100);
338632b0b53SRijo Thomas }
339632b0b53SRijo Thomas
340632b0b53SRijo Thomas dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n",
341632b0b53SRijo Thomas resp->cmd_id);
342632b0b53SRijo Thomas
343632b0b53SRijo Thomas psp_dead = true;
344632b0b53SRijo Thomas
345632b0b53SRijo Thomas return -ETIMEDOUT;
346632b0b53SRijo Thomas }
347632b0b53SRijo Thomas
psp_tee_process_cmd(enum tee_cmd_id cmd_id,void * buf,size_t len,u32 * status)348632b0b53SRijo Thomas int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
349632b0b53SRijo Thomas u32 *status)
350632b0b53SRijo Thomas {
351632b0b53SRijo Thomas struct psp_device *psp = psp_get_master_device();
352632b0b53SRijo Thomas struct psp_tee_device *tee;
353632b0b53SRijo Thomas struct tee_ring_cmd *resp;
354632b0b53SRijo Thomas int ret;
355632b0b53SRijo Thomas
356632b0b53SRijo Thomas if (!buf || !status || !len || len > sizeof(resp->buf))
357632b0b53SRijo Thomas return -EINVAL;
358632b0b53SRijo Thomas
359632b0b53SRijo Thomas *status = 0;
360632b0b53SRijo Thomas
361632b0b53SRijo Thomas if (!psp || !psp->tee_data)
362632b0b53SRijo Thomas return -ENODEV;
363632b0b53SRijo Thomas
364632b0b53SRijo Thomas if (psp_dead)
365632b0b53SRijo Thomas return -EBUSY;
366632b0b53SRijo Thomas
367632b0b53SRijo Thomas tee = psp->tee_data;
368632b0b53SRijo Thomas
369632b0b53SRijo Thomas ret = tee_submit_cmd(tee, cmd_id, buf, len, &resp);
370632b0b53SRijo Thomas if (ret)
371632b0b53SRijo Thomas return ret;
372632b0b53SRijo Thomas
373632b0b53SRijo Thomas ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT);
37400aa6e65SRijo Thomas if (ret) {
37500aa6e65SRijo Thomas resp->flag = CMD_RESPONSE_TIMEDOUT;
376632b0b53SRijo Thomas return ret;
37700aa6e65SRijo Thomas }
378632b0b53SRijo Thomas
379632b0b53SRijo Thomas memcpy(buf, &resp->buf[0], len);
380632b0b53SRijo Thomas *status = resp->status;
381632b0b53SRijo Thomas
38200aa6e65SRijo Thomas resp->flag = CMD_RESPONSE_COPIED;
38300aa6e65SRijo Thomas
384632b0b53SRijo Thomas return 0;
385632b0b53SRijo Thomas }
386632b0b53SRijo Thomas EXPORT_SYMBOL(psp_tee_process_cmd);
387bade7e1fSRijo Thomas
psp_check_tee_status(void)388bade7e1fSRijo Thomas int psp_check_tee_status(void)
389bade7e1fSRijo Thomas {
390bade7e1fSRijo Thomas struct psp_device *psp = psp_get_master_device();
391bade7e1fSRijo Thomas
392bade7e1fSRijo Thomas if (!psp || !psp->tee_data)
393bade7e1fSRijo Thomas return -ENODEV;
394bade7e1fSRijo Thomas
395bade7e1fSRijo Thomas return 0;
396bade7e1fSRijo Thomas }
397bade7e1fSRijo Thomas EXPORT_SYMBOL(psp_check_tee_status);
398