aboutsummaryrefslogtreecommitdiff
path: root/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
blob: 11f382a05392b1b68725e2c98faaf78cab175268 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*
 * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions.
 */

#include <errno.h>
#include <string.h>

#include <common/debug.h>
#include <common/runtime_svc.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>

#include "ipi_mailbox_svc.h"
#include "../zynqmp_ipi.h"
#include "../zynqmp_private.h"
#include "../../../services/spd/trusty/smcall.h"

/*********************************************************************
 * Macros definitions
 ********************************************************************/

/* IPI SMC calls macros: */
#define IPI_SMC_OPEN_IRQ_MASK		0x00000001U /* IRQ enable bit in IPI
						     * open SMC call
						     */
#define IPI_SMC_NOTIFY_BLOCK_MASK	0x00000001U /* Flag to indicate if
						     * IPI notification needs
						     * to be blocking.
						     */
#define IPI_SMC_ENQUIRY_DIRQ_MASK	0x00000001U /* Flag to indicate if
						     * notification interrupt
						     * to be disabled.
						     */
#define IPI_SMC_ACK_EIRQ_MASK		0x00000001U /* Flag to indicate if
						     * notification interrupt
						     * to be enable.
						     */

#define UNSIGNED32_MASK			0xFFFFFFFFU /* 32bit mask */

/**
 * ipi_smc_handler() - SMC handler for IPI SMC calls
 *
 * @smc_fid - Function identifier
 * @x1 - x4 - Arguments
 * @cookie  - Unused
 * @handler - Pointer to caller's context structure
 *
 * @return  - Unused
 *
 * Determines that smc_fid is valid and supported PM SMC Function ID from the
 * list of pm_api_ids, otherwise completes the request with
 * the unknown SMC Function ID
 *
 * The SMC calls for PM service are forwarded from SIP Service SMC handler
 * function with rt_svc_handle signature
 */
uint64_t 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)
{
	int ret;
	uint32_t ipi_local_id;
	uint32_t ipi_remote_id;
	unsigned int is_secure;

	ipi_local_id = x1 & UNSIGNED32_MASK;
	ipi_remote_id = x2 & UNSIGNED32_MASK;

	if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP)
		is_secure = 1;
	else
		is_secure = 0;

	/* Validate IPI mailbox access */
	ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure);
	if (ret)
		SMC_RET1(handle, ret);

	switch (SMC_FUNCTION(smc_fid)) {
	case IPI_MAILBOX_OPEN:
		ipi_mb_open(ipi_local_id, ipi_remote_id);
		SMC_RET1(handle, 0);
	case IPI_MAILBOX_RELEASE:
		ipi_mb_release(ipi_local_id, ipi_remote_id);
		SMC_RET1(handle, 0);
	case IPI_MAILBOX_STATUS_ENQUIRY:
	{
		int disable_irq;

		disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0;
		ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id);
		if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq)
			ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
		SMC_RET1(handle, ret);
	}
	case IPI_MAILBOX_NOTIFY:
	{
		uint32_t is_blocking;

		is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0;
		ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking);
		SMC_RET1(handle, 0);
	}
	case IPI_MAILBOX_ACK:
	{
		int enable_irq;

		enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0;
		ipi_mb_ack(ipi_local_id, ipi_remote_id);
		if (enable_irq)
			ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
		SMC_RET1(handle, 0);
	}
	case IPI_MAILBOX_ENABLE_IRQ:
		ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
		SMC_RET1(handle, 0);
	case IPI_MAILBOX_DISABLE_IRQ:
		ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
		SMC_RET1(handle, 0);
	default:
		WARN("Unimplemented IPI service call: 0x%x\n", smc_fid);
		SMC_RET1(handle, SMC_UNK);
	}
}