1 /*
2  * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions.
9  */
10 
11 #include <errno.h>
12 #include <string.h>
13 
14 #include <common/debug.h>
15 #include <common/runtime_svc.h>
16 #include <lib/bakery_lock.h>
17 #include <lib/mmio.h>
18 
19 #include <ipi.h>
20 #include <plat_ipi.h>
21 #include <plat_private.h>
22 
23 #include "ipi_mailbox_svc.h"
24 #include "../../../services/spd/trusty/smcall.h"
25 
26 /*********************************************************************
27  * Macros definitions
28  ********************************************************************/
29 
30 /* IPI SMC calls macros: */
31 #define IPI_SMC_OPEN_IRQ_MASK		0x00000001U /* IRQ enable bit in IPI
32 						     * open SMC call
33 						     */
34 #define IPI_SMC_NOTIFY_BLOCK_MASK	0x00000001U /* Flag to indicate if
35 						     * IPI notification needs
36 						     * to be blocking.
37 						     */
38 #define IPI_SMC_ENQUIRY_DIRQ_MASK	0x00000001U /* Flag to indicate if
39 						     * notification interrupt
40 						     * to be disabled.
41 						     */
42 #define IPI_SMC_ACK_EIRQ_MASK		0x00000001U /* Flag to indicate if
43 						     * notification interrupt
44 						     * to be enable.
45 						     */
46 
47 #define UNSIGNED32_MASK			0xFFFFFFFFU /* 32bit mask */
48 
49 /**
50  * ipi_smc_handler() - SMC handler for IPI SMC calls
51  *
52  * @smc_fid - Function identifier
53  * @x1 - x4 - Arguments
54  * @cookie  - Unused
55  * @handler - Pointer to caller's context structure
56  *
57  * @return  - Unused
58  *
59  * Determines that smc_fid is valid and supported PM SMC Function ID from the
60  * list of pm_api_ids, otherwise completes the request with
61  * the unknown SMC Function ID
62  *
63  * The SMC calls for PM service are forwarded from SIP Service SMC handler
64  * function with rt_svc_handle signature
65  */
ipi_smc_handler(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)66 uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
67 			 uint64_t x3, uint64_t x4, void *cookie,
68 			 void *handle, uint64_t flags)
69 {
70 	int ret;
71 	uint32_t ipi_local_id;
72 	uint32_t ipi_remote_id;
73 	unsigned int is_secure;
74 
75 	ipi_local_id = x1 & UNSIGNED32_MASK;
76 	ipi_remote_id = x2 & UNSIGNED32_MASK;
77 
78 	if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP)
79 		is_secure = 1;
80 	else
81 		is_secure = 0;
82 
83 	/* Validate IPI mailbox access */
84 	ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure);
85 	if (ret)
86 		SMC_RET1(handle, ret);
87 
88 	switch (SMC_FUNCTION(smc_fid)) {
89 	case IPI_MAILBOX_OPEN:
90 		ipi_mb_open(ipi_local_id, ipi_remote_id);
91 		SMC_RET1(handle, 0);
92 	case IPI_MAILBOX_RELEASE:
93 		ipi_mb_release(ipi_local_id, ipi_remote_id);
94 		SMC_RET1(handle, 0);
95 	case IPI_MAILBOX_STATUS_ENQUIRY:
96 	{
97 		int disable_irq;
98 
99 		disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0;
100 		ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id);
101 		if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq)
102 			ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
103 		SMC_RET1(handle, ret);
104 	}
105 	case IPI_MAILBOX_NOTIFY:
106 	{
107 		uint32_t is_blocking;
108 
109 		is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0;
110 		ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking);
111 		SMC_RET1(handle, 0);
112 	}
113 	case IPI_MAILBOX_ACK:
114 	{
115 		int enable_irq;
116 
117 		enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0;
118 		ipi_mb_ack(ipi_local_id, ipi_remote_id);
119 		if (enable_irq)
120 			ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
121 		SMC_RET1(handle, 0);
122 	}
123 	case IPI_MAILBOX_ENABLE_IRQ:
124 		ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
125 		SMC_RET1(handle, 0);
126 	case IPI_MAILBOX_DISABLE_IRQ:
127 		ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
128 		SMC_RET1(handle, 0);
129 	default:
130 		WARN("Unimplemented IPI service call: 0x%x\n", smc_fid);
131 		SMC_RET1(handle, SMC_UNK);
132 	}
133 }
134