xref: /netbsd-src/sys/dev/acpi/qcomscm.c (revision c95a3ae2317896c4d793c18beffdb76c65ba8b57)
1*c95a3ae2Sjmcneill /* $NetBSD: qcomscm.c,v 1.1 2024/12/30 12:31:10 jmcneill Exp $ */
2*c95a3ae2Sjmcneill /* $OpenBSD: qcscm.c,v 1.9 2024/08/04 15:30:08 kettenis Exp $ */
3*c95a3ae2Sjmcneill /*
4*c95a3ae2Sjmcneill  * Copyright (c) 2022 Patrick Wildt <patrick@blueri.se>
5*c95a3ae2Sjmcneill  *
6*c95a3ae2Sjmcneill  * Permission to use, copy, modify, and distribute this software for any
7*c95a3ae2Sjmcneill  * purpose with or without fee is hereby granted, provided that the above
8*c95a3ae2Sjmcneill  * copyright notice and this permission notice appear in all copies.
9*c95a3ae2Sjmcneill  *
10*c95a3ae2Sjmcneill  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*c95a3ae2Sjmcneill  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*c95a3ae2Sjmcneill  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*c95a3ae2Sjmcneill  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*c95a3ae2Sjmcneill  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*c95a3ae2Sjmcneill  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*c95a3ae2Sjmcneill  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*c95a3ae2Sjmcneill  */
18*c95a3ae2Sjmcneill 
19*c95a3ae2Sjmcneill #include <sys/param.h>
20*c95a3ae2Sjmcneill #include <sys/systm.h>
21*c95a3ae2Sjmcneill #include <sys/device.h>
22*c95a3ae2Sjmcneill #include <sys/kmem.h>
23*c95a3ae2Sjmcneill #include <sys/bus.h>
24*c95a3ae2Sjmcneill #include <sys/uuid.h>
25*c95a3ae2Sjmcneill 
26*c95a3ae2Sjmcneill #include <dev/efi/efi.h>
27*c95a3ae2Sjmcneill #include <dev/acpi/acpivar.h>
28*c95a3ae2Sjmcneill #include <dev/acpi/qcomscm.h>
29*c95a3ae2Sjmcneill 
30*c95a3ae2Sjmcneill #define ARM_SMCCC_STD_CALL			(0U << 31)
31*c95a3ae2Sjmcneill #define ARM_SMCCC_FAST_CALL			(1U << 31)
32*c95a3ae2Sjmcneill #define ARM_SMCCC_LP64				(1U << 30)
33*c95a3ae2Sjmcneill #define ARM_SMCCC_OWNER_SIP			2
34*c95a3ae2Sjmcneill 
35*c95a3ae2Sjmcneill #define QCTEE_TZ_OWNER_TZ_APPS			48
36*c95a3ae2Sjmcneill #define QCTEE_TZ_OWNER_QSEE_OS			50
37*c95a3ae2Sjmcneill 
38*c95a3ae2Sjmcneill #define QCTEE_TZ_SVC_APP_ID_PLACEHOLDER		0
39*c95a3ae2Sjmcneill #define QCTEE_TZ_SVC_APP_MGR			1
40*c95a3ae2Sjmcneill 
41*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_SUCCESS			0
42*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_INCOMPLETE		1
43*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_BLOCKED_ON_LISTENER	2
44*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_FAILURE			0xffffffff
45*c95a3ae2Sjmcneill 
46*c95a3ae2Sjmcneill #define QCTEE_OS_SCM_RES_APP_ID			0xee01
47*c95a3ae2Sjmcneill #define QCTEE_OS_SCM_RES_QSEOS_LISTENER_ID	0xee02
48*c95a3ae2Sjmcneill 
49*c95a3ae2Sjmcneill #define QCTEE_UEFI_GET_VARIABLE			0x8000
50*c95a3ae2Sjmcneill #define QCTEE_UEFI_SET_VARIABLE			0x8001
51*c95a3ae2Sjmcneill #define QCTEE_UEFI_GET_NEXT_VARIABLE		0x8002
52*c95a3ae2Sjmcneill #define QCTEE_UEFI_QUERY_VARIABLE_INFO		0x8003
53*c95a3ae2Sjmcneill 
54*c95a3ae2Sjmcneill #define QCTEE_UEFI_SUCCESS			0
55*c95a3ae2Sjmcneill #define QCTEE_UEFI_BUFFER_TOO_SMALL		0x80000005
56*c95a3ae2Sjmcneill #define QCTEE_UEFI_DEVICE_ERROR			0x80000007
57*c95a3ae2Sjmcneill #define QCTEE_UEFI_NOT_FOUND			0x8000000e
58*c95a3ae2Sjmcneill 
59*c95a3ae2Sjmcneill #define QCSCM_SVC_PIL			0x02
60*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_INIT_IMAGE	0x01
61*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_MEM_SETUP		0x02
62*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_AUTH_AND_RESET	0x05
63*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_SHUTDOWN		0x06
64*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_IS_SUPPORTED	0x07
65*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_MSS_RESET		0x0a
66*c95a3ae2Sjmcneill 
67*c95a3ae2Sjmcneill #define QCSCM_INTERRUPTED		1
68*c95a3ae2Sjmcneill #define QCSCM_EBUSY			-22
69*c95a3ae2Sjmcneill 
70*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_NUM(x)		(((x) & 0xf) << 0)
71*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE(x, y)	(((y) & 0x3) << (4 + 2 * (x)))
72*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_VAL		0
73*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_RO		1
74*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_RW		2
75*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_BUFVAL	3
76*c95a3ae2Sjmcneill 
77*c95a3ae2Sjmcneill #define EFI_VARIABLE_NON_VOLATILE	0x00000001
78*c95a3ae2Sjmcneill #define EFI_VARIABLE_BOOTSERVICE_ACCESS	0x00000002
79*c95a3ae2Sjmcneill #define EFI_VARIABLE_RUNTIME_ACCESS	0x00000004
80*c95a3ae2Sjmcneill 
81*c95a3ae2Sjmcneill #define UNIX_GPS_EPOCH_OFFSET		315964800
82*c95a3ae2Sjmcneill 
83*c95a3ae2Sjmcneill #define EFI_VAR_RTCINFO			__UNCONST(u"RTCInfo")
84*c95a3ae2Sjmcneill 
85*c95a3ae2Sjmcneill extern struct arm32_bus_dma_tag arm_generic_dma_tag;
86*c95a3ae2Sjmcneill 
87*c95a3ae2Sjmcneill struct qcscm_dmamem {
88*c95a3ae2Sjmcneill 	bus_dmamap_t		qdm_map;
89*c95a3ae2Sjmcneill 	bus_dma_segment_t	qdm_seg;
90*c95a3ae2Sjmcneill 	size_t			qdm_size;
91*c95a3ae2Sjmcneill 	void			*qdm_kva;
92*c95a3ae2Sjmcneill };
93*c95a3ae2Sjmcneill 
94*c95a3ae2Sjmcneill #define QCSCM_DMA_MAP(_qdm)		((_qdm)->qdm_map)
95*c95a3ae2Sjmcneill #define QCSCM_DMA_LEN(_qdm)		((_qdm)->qdm_size)
96*c95a3ae2Sjmcneill #define QCSCM_DMA_DVA(_qdm)		((uint64_t)(_qdm)->qdm_map->dm_segs[0].ds_addr)
97*c95a3ae2Sjmcneill #define QCSCM_DMA_KVA(_qdm, off)	((void *)((uintptr_t)(_qdm)->qdm_kva + (off)))
98*c95a3ae2Sjmcneill 
99*c95a3ae2Sjmcneill static struct uuid qcscm_uefi_rtcinfo_guid =
100*c95a3ae2Sjmcneill   { 0x882f8c2b, 0x9646, 0x435f,
101*c95a3ae2Sjmcneill     0x8d, 0xe5, { 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd } };
102*c95a3ae2Sjmcneill 
103*c95a3ae2Sjmcneill struct qcscm_softc {
104*c95a3ae2Sjmcneill 	device_t		sc_dev;
105*c95a3ae2Sjmcneill 	bus_dma_tag_t		sc_dmat;
106*c95a3ae2Sjmcneill 
107*c95a3ae2Sjmcneill 	struct qcscm_dmamem	*sc_extarg;
108*c95a3ae2Sjmcneill 	uint32_t		sc_uefi_id;
109*c95a3ae2Sjmcneill };
110*c95a3ae2Sjmcneill 
111*c95a3ae2Sjmcneill static int	qcscm_match(device_t, cfdata_t, void *);
112*c95a3ae2Sjmcneill static void	qcscm_attach(device_t, device_t, void *);
113*c95a3ae2Sjmcneill 
114*c95a3ae2Sjmcneill CFATTACH_DECL_NEW(qcomscm, sizeof(struct qcscm_softc),
115*c95a3ae2Sjmcneill     qcscm_match, qcscm_attach, NULL, NULL);
116*c95a3ae2Sjmcneill 
117*c95a3ae2Sjmcneill static inline void	qcscm_smc_exec(uint64_t *, uint64_t *);
118*c95a3ae2Sjmcneill int	qcscm_smc_call(struct qcscm_softc *, uint8_t, uint8_t, uint8_t,
119*c95a3ae2Sjmcneill 	    uint32_t, uint64_t *, int, uint64_t *);
120*c95a3ae2Sjmcneill int	qcscm_tee_app_get_id(struct qcscm_softc *, const char *, uint32_t *);
121*c95a3ae2Sjmcneill int	qcscm_tee_app_send(struct qcscm_softc *, uint32_t, uint64_t, uint64_t,
122*c95a3ae2Sjmcneill 	    uint64_t, uint64_t);
123*c95a3ae2Sjmcneill 
124*c95a3ae2Sjmcneill efi_status qcscm_uefi_get_variable(struct qcscm_softc *, efi_char *,
125*c95a3ae2Sjmcneill 	    int, struct uuid *, uint32_t *, uint8_t *, int *);
126*c95a3ae2Sjmcneill efi_status qcscm_uefi_set_variable(struct qcscm_softc *, efi_char *,
127*c95a3ae2Sjmcneill 	    int, struct uuid *, uint32_t, uint8_t *, int);
128*c95a3ae2Sjmcneill efi_status qcscm_uefi_get_next_variable(struct qcscm_softc *,
129*c95a3ae2Sjmcneill 	    efi_char *, int *, struct uuid *);
130*c95a3ae2Sjmcneill 
131*c95a3ae2Sjmcneill efi_status qcscm_efi_get_variable(efi_char *, struct uuid *, uint32_t *,
132*c95a3ae2Sjmcneill 	    u_long *, void *);
133*c95a3ae2Sjmcneill efi_status qcscm_efi_set_variable(efi_char *, struct uuid *, uint32_t,
134*c95a3ae2Sjmcneill 	    u_long, void *);
135*c95a3ae2Sjmcneill efi_status qcscm_efi_get_next_variable_name(u_long *, efi_char *, struct uuid *);
136*c95a3ae2Sjmcneill 
137*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG
138*c95a3ae2Sjmcneill void	qcscm_uefi_dump_variables(struct qcscm_softc *);
139*c95a3ae2Sjmcneill void	qcscm_uefi_dump_variable(struct qcscm_softc *, efi_char *, int,
140*c95a3ae2Sjmcneill 	    struct uuid *);
141*c95a3ae2Sjmcneill #endif
142*c95a3ae2Sjmcneill 
143*c95a3ae2Sjmcneill int	qcscm_uefi_rtc_get(uint32_t *);
144*c95a3ae2Sjmcneill int	qcscm_uefi_rtc_set(uint32_t);
145*c95a3ae2Sjmcneill 
146*c95a3ae2Sjmcneill struct qcscm_dmamem *
147*c95a3ae2Sjmcneill 	 qcscm_dmamem_alloc(struct qcscm_softc *, bus_size_t, bus_size_t);
148*c95a3ae2Sjmcneill void	 qcscm_dmamem_free(struct qcscm_softc *, struct qcscm_dmamem *);
149*c95a3ae2Sjmcneill 
150*c95a3ae2Sjmcneill struct qcscm_softc *qcscm_sc;
151*c95a3ae2Sjmcneill 
152*c95a3ae2Sjmcneill static const struct device_compatible_entry compat_data[] = {
153*c95a3ae2Sjmcneill 	{ .compat = "QCOM04DD" },
154*c95a3ae2Sjmcneill 	DEVICE_COMPAT_EOL
155*c95a3ae2Sjmcneill };
156*c95a3ae2Sjmcneill 
157*c95a3ae2Sjmcneill static int
158*c95a3ae2Sjmcneill qcscm_match(device_t parent, cfdata_t cf, void *aux)
159*c95a3ae2Sjmcneill {
160*c95a3ae2Sjmcneill 	struct acpi_attach_args *aa = aux;
161*c95a3ae2Sjmcneill 
162*c95a3ae2Sjmcneill 	return acpi_compatible_match(aa, compat_data);
163*c95a3ae2Sjmcneill }
164*c95a3ae2Sjmcneill 
165*c95a3ae2Sjmcneill static void
166*c95a3ae2Sjmcneill qcscm_attach(device_t parent, device_t self, void *aux)
167*c95a3ae2Sjmcneill {
168*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = device_private(self);
169*c95a3ae2Sjmcneill 	int error;
170*c95a3ae2Sjmcneill 
171*c95a3ae2Sjmcneill 	sc->sc_dev = self;
172*c95a3ae2Sjmcneill 	error = bus_dmatag_subregion(&arm_generic_dma_tag,
173*c95a3ae2Sjmcneill 	    0, __MASK(32), &sc->sc_dmat, 0);
174*c95a3ae2Sjmcneill 	KASSERT(error == 0);
175*c95a3ae2Sjmcneill 
176*c95a3ae2Sjmcneill 	sc->sc_extarg = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8);
177*c95a3ae2Sjmcneill 	if (sc->sc_extarg == NULL) {
178*c95a3ae2Sjmcneill 		aprint_error(": can't allocate memory for extended args\n");
179*c95a3ae2Sjmcneill 		return;
180*c95a3ae2Sjmcneill 	}
181*c95a3ae2Sjmcneill 
182*c95a3ae2Sjmcneill 	aprint_naive("\n");
183*c95a3ae2Sjmcneill 	aprint_normal("\n");
184*c95a3ae2Sjmcneill 
185*c95a3ae2Sjmcneill #if notyet
186*c95a3ae2Sjmcneill 	error = qcscm_tee_app_get_id(sc, "qcom.tz.uefisecapp", &sc->sc_uefi_id);
187*c95a3ae2Sjmcneill 	if (error != 0) {
188*c95a3ae2Sjmcneill 		aprint_error_dev(self, "can't retrieve UEFI App: %d\n", error);
189*c95a3ae2Sjmcneill 		sc->sc_uefi_id = UINT32_MAX;
190*c95a3ae2Sjmcneill 	}
191*c95a3ae2Sjmcneill #else
192*c95a3ae2Sjmcneill 	sc->sc_uefi_id = UINT32_MAX;
193*c95a3ae2Sjmcneill #endif
194*c95a3ae2Sjmcneill 
195*c95a3ae2Sjmcneill 	qcscm_sc = sc;
196*c95a3ae2Sjmcneill 
197*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG
198*c95a3ae2Sjmcneill 	qcscm_uefi_dump_variables(sc);
199*c95a3ae2Sjmcneill 	qcscm_uefi_dump_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO),
200*c95a3ae2Sjmcneill 	    &qcscm_uefi_rtcinfo_guid);
201*c95a3ae2Sjmcneill #endif
202*c95a3ae2Sjmcneill }
203*c95a3ae2Sjmcneill 
204*c95a3ae2Sjmcneill /* Expects an uint64_t[18] */
205*c95a3ae2Sjmcneill static inline void
206*c95a3ae2Sjmcneill qcscm_smc_exec(uint64_t *in, uint64_t *out)
207*c95a3ae2Sjmcneill {
208*c95a3ae2Sjmcneill 	asm volatile(
209*c95a3ae2Sjmcneill 	    "ldp x0, x1, [%[in], #0]\n"
210*c95a3ae2Sjmcneill 	    "ldp x2, x3, [%[in], #16]\n"
211*c95a3ae2Sjmcneill 	    "ldp x4, x5, [%[in], #32]\n"
212*c95a3ae2Sjmcneill 	    "ldp x6, x7, [%[in], #48]\n"
213*c95a3ae2Sjmcneill 	    "ldp x8, x9, [%[in], #64]\n"
214*c95a3ae2Sjmcneill 	    "ldp x10, x11, [%[in], #80]\n"
215*c95a3ae2Sjmcneill 	    "ldp x12, x13, [%[in], #96]\n"
216*c95a3ae2Sjmcneill 	    "ldp x14, x15, [%[in], #112]\n"
217*c95a3ae2Sjmcneill 	    "ldp x16, x17, [%[in], #128]\n"
218*c95a3ae2Sjmcneill 	    "smc #0\n"
219*c95a3ae2Sjmcneill 	    "stp x0, x1, [%[out], #0]\n"
220*c95a3ae2Sjmcneill 	    "stp x2, x3, [%[out], #16]\n"
221*c95a3ae2Sjmcneill 	    "stp x4, x5, [%[out], #32]\n"
222*c95a3ae2Sjmcneill 	    "stp x6, x7, [%[out], #48]\n"
223*c95a3ae2Sjmcneill 	    "stp x8, x9, [%[out], #64]\n"
224*c95a3ae2Sjmcneill 	    "stp x10, x11, [%[out], #80]\n"
225*c95a3ae2Sjmcneill 	    "stp x12, x13, [%[out], #96]\n"
226*c95a3ae2Sjmcneill 	    "stp x14, x15, [%[out], #112]\n"
227*c95a3ae2Sjmcneill 	    "stp x16, x17, [%[out], #128]\n"
228*c95a3ae2Sjmcneill 	    :
229*c95a3ae2Sjmcneill 	    : [in] "r" (in), [out] "r" (out)
230*c95a3ae2Sjmcneill 	    : "x0", "x1", "x2", "x3", "x4", "x5",
231*c95a3ae2Sjmcneill 	      "x6", "x7", "x8", "x9", "x10", "x11",
232*c95a3ae2Sjmcneill 	      "x12", "x13", "x14", "x15", "x16", "x17",
233*c95a3ae2Sjmcneill 	      "memory");
234*c95a3ae2Sjmcneill }
235*c95a3ae2Sjmcneill 
236*c95a3ae2Sjmcneill int
237*c95a3ae2Sjmcneill qcscm_smc_call(struct qcscm_softc *sc, uint8_t owner, uint8_t svc, uint8_t cmd,
238*c95a3ae2Sjmcneill     uint32_t arginfo, uint64_t *args, int arglen, uint64_t *res)
239*c95a3ae2Sjmcneill {
240*c95a3ae2Sjmcneill 	uint64_t smcreq[18] = { 0 }, smcres[18] = { 0 };
241*c95a3ae2Sjmcneill 	uint64_t *smcextreq;
242*c95a3ae2Sjmcneill 	int i, busy_retry;
243*c95a3ae2Sjmcneill 
244*c95a3ae2Sjmcneill 	/* 4 of our 10 possible args fit into x2-x5 */
245*c95a3ae2Sjmcneill 	smcreq[0] = ARM_SMCCC_STD_CALL | ARM_SMCCC_LP64 |
246*c95a3ae2Sjmcneill 	    owner << 24 | svc << 8 | cmd;
247*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG_SMC
248*c95a3ae2Sjmcneill 	device_printf(sc->sc_dev, "owner %#x svc %#x cmd %#x req %#lx\n",
249*c95a3ae2Sjmcneill 	    owner, svc, cmd, smcreq[0]);
250*c95a3ae2Sjmcneill #endif
251*c95a3ae2Sjmcneill 	smcreq[1] = arginfo;
252*c95a3ae2Sjmcneill 	for (i = 0; i < uimin(arglen, 4); i++)
253*c95a3ae2Sjmcneill 		smcreq[2 + i] = args[i];
254*c95a3ae2Sjmcneill 
255*c95a3ae2Sjmcneill 	/* In case we have more than 4, use x5 as ptr to extra args */
256*c95a3ae2Sjmcneill 	if (arglen > 4) {
257*c95a3ae2Sjmcneill 		smcreq[5] = QCSCM_DMA_DVA(sc->sc_extarg);
258*c95a3ae2Sjmcneill 		smcextreq = QCSCM_DMA_KVA(sc->sc_extarg, 0);
259*c95a3ae2Sjmcneill 		for (i = 0; i < uimin(arglen - 3, 7); i++) {
260*c95a3ae2Sjmcneill 			smcextreq[i] = args[3 + i];
261*c95a3ae2Sjmcneill 		}
262*c95a3ae2Sjmcneill 		cpu_drain_writebuf();
263*c95a3ae2Sjmcneill 	}
264*c95a3ae2Sjmcneill 
265*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG_SMC
266*c95a3ae2Sjmcneill 	device_printf(sc->sc_dev, "smcreq[before]:");
267*c95a3ae2Sjmcneill 	for (i = 0; i < __arraycount(smcreq); i++) {
268*c95a3ae2Sjmcneill 		printf(" %#lx", smcreq[i]);
269*c95a3ae2Sjmcneill 	}
270*c95a3ae2Sjmcneill 	printf("\n");
271*c95a3ae2Sjmcneill #endif
272*c95a3ae2Sjmcneill 	for (busy_retry = 20; busy_retry > 0; busy_retry--) {
273*c95a3ae2Sjmcneill 		int intr_retry = 1000000;
274*c95a3ae2Sjmcneill 		for (;;) {
275*c95a3ae2Sjmcneill 			qcscm_smc_exec(smcreq, smcres);
276*c95a3ae2Sjmcneill 			/* If the call gets interrupted, try again and re-pass x0/x6 */
277*c95a3ae2Sjmcneill 			if (smcres[0] == QCSCM_INTERRUPTED) {
278*c95a3ae2Sjmcneill 				if (--intr_retry == 0) {
279*c95a3ae2Sjmcneill 					break;
280*c95a3ae2Sjmcneill 				}
281*c95a3ae2Sjmcneill 				smcreq[0] = smcres[0];
282*c95a3ae2Sjmcneill 				smcreq[6] = smcres[6];
283*c95a3ae2Sjmcneill 				continue;
284*c95a3ae2Sjmcneill 			}
285*c95a3ae2Sjmcneill 			break;
286*c95a3ae2Sjmcneill 		}
287*c95a3ae2Sjmcneill 
288*c95a3ae2Sjmcneill 		if (smcres[0] != QCSCM_EBUSY) {
289*c95a3ae2Sjmcneill 			break;
290*c95a3ae2Sjmcneill 		}
291*c95a3ae2Sjmcneill 		delay(30000);
292*c95a3ae2Sjmcneill 	}
293*c95a3ae2Sjmcneill 
294*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG_SMC
295*c95a3ae2Sjmcneill 	device_printf(sc->sc_dev, "smcreq[after]:");
296*c95a3ae2Sjmcneill 	for (i = 0; i < __arraycount(smcreq); i++) {
297*c95a3ae2Sjmcneill 		printf(" %#lx", smcreq[i]);
298*c95a3ae2Sjmcneill 	}
299*c95a3ae2Sjmcneill 	printf("\n");
300*c95a3ae2Sjmcneill 	device_printf(sc->sc_dev, "smcres[after]:");
301*c95a3ae2Sjmcneill 	for (i = 0; i < __arraycount(smcres); i++) {
302*c95a3ae2Sjmcneill 		printf(" %#lx", smcres[i]);
303*c95a3ae2Sjmcneill 	}
304*c95a3ae2Sjmcneill 	printf("\n");
305*c95a3ae2Sjmcneill #endif
306*c95a3ae2Sjmcneill 
307*c95a3ae2Sjmcneill 	if (res) {
308*c95a3ae2Sjmcneill 		res[0] = smcres[1];
309*c95a3ae2Sjmcneill 		res[1] = smcres[2];
310*c95a3ae2Sjmcneill 		res[2] = smcres[3];
311*c95a3ae2Sjmcneill 	}
312*c95a3ae2Sjmcneill 
313*c95a3ae2Sjmcneill 	return smcres[0];
314*c95a3ae2Sjmcneill }
315*c95a3ae2Sjmcneill 
316*c95a3ae2Sjmcneill /* Retrieve id of app running in TEE by name */
317*c95a3ae2Sjmcneill int
318*c95a3ae2Sjmcneill qcscm_tee_app_get_id(struct qcscm_softc *sc, const char *name, uint32_t *id)
319*c95a3ae2Sjmcneill {
320*c95a3ae2Sjmcneill 	struct qcscm_dmamem *qdm;
321*c95a3ae2Sjmcneill 	uint64_t res[3];
322*c95a3ae2Sjmcneill 	uint64_t args[2];
323*c95a3ae2Sjmcneill 	uint32_t arginfo;
324*c95a3ae2Sjmcneill 	int ret;
325*c95a3ae2Sjmcneill 
326*c95a3ae2Sjmcneill 	/* Max name length is 64 */
327*c95a3ae2Sjmcneill 	if (strlen(name) > 64)
328*c95a3ae2Sjmcneill 		return EINVAL;
329*c95a3ae2Sjmcneill 
330*c95a3ae2Sjmcneill 	/* Alloc some phys mem to hold the name */
331*c95a3ae2Sjmcneill 	qdm = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8);
332*c95a3ae2Sjmcneill 	if (qdm == NULL)
333*c95a3ae2Sjmcneill 		return ENOMEM;
334*c95a3ae2Sjmcneill 
335*c95a3ae2Sjmcneill 	/* Copy name of app we want to get an id for to page */
336*c95a3ae2Sjmcneill 	memcpy(QCSCM_DMA_KVA(qdm, 0), name, strlen(name));
337*c95a3ae2Sjmcneill 
338*c95a3ae2Sjmcneill 	/* Pass address of name and length */
339*c95a3ae2Sjmcneill 	arginfo = QCSCM_ARGINFO_NUM(__arraycount(args));
340*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_RW);
341*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL);
342*c95a3ae2Sjmcneill 	args[0] = QCSCM_DMA_DVA(qdm);
343*c95a3ae2Sjmcneill 	args[1] = strlen(name);
344*c95a3ae2Sjmcneill 
345*c95a3ae2Sjmcneill 	cpu_drain_writebuf();
346*c95a3ae2Sjmcneill 
347*c95a3ae2Sjmcneill 	/* Make call into TEE */
348*c95a3ae2Sjmcneill 	ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_QSEE_OS, QCTEE_TZ_SVC_APP_MGR,
349*c95a3ae2Sjmcneill 	    0x03, arginfo, args, __arraycount(args), res);
350*c95a3ae2Sjmcneill 
351*c95a3ae2Sjmcneill 	/* If the call succeeded, check the response status */
352*c95a3ae2Sjmcneill 	if (ret == 0)
353*c95a3ae2Sjmcneill 		ret = res[0];
354*c95a3ae2Sjmcneill 
355*c95a3ae2Sjmcneill 	/* If the response status is successful as well, retrieve data */
356*c95a3ae2Sjmcneill 	if (ret == 0)
357*c95a3ae2Sjmcneill 		*id = res[2];
358*c95a3ae2Sjmcneill 
359*c95a3ae2Sjmcneill 	qcscm_dmamem_free(sc, qdm);
360*c95a3ae2Sjmcneill 	return ret;
361*c95a3ae2Sjmcneill }
362*c95a3ae2Sjmcneill 
363*c95a3ae2Sjmcneill /* Message interface to app running in TEE */
364*c95a3ae2Sjmcneill int
365*c95a3ae2Sjmcneill qcscm_tee_app_send(struct qcscm_softc *sc, uint32_t id, uint64_t req_phys,
366*c95a3ae2Sjmcneill     uint64_t req_len, uint64_t rsp_phys, uint64_t rsp_len)
367*c95a3ae2Sjmcneill {
368*c95a3ae2Sjmcneill 	uint64_t res[3];
369*c95a3ae2Sjmcneill 	uint64_t args[5];
370*c95a3ae2Sjmcneill 	uint32_t arginfo;
371*c95a3ae2Sjmcneill 	int ret;
372*c95a3ae2Sjmcneill 
373*c95a3ae2Sjmcneill 	/* Pass id of app we target, plus request and response buffers */
374*c95a3ae2Sjmcneill 	arginfo = QCSCM_ARGINFO_NUM(__arraycount(args));
375*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL);
376*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW);
377*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL);
378*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(3, QCSCM_ARGINFO_TYPE_RW);
379*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(4, QCSCM_ARGINFO_TYPE_VAL);
380*c95a3ae2Sjmcneill 	args[0] = id;
381*c95a3ae2Sjmcneill 	args[1] = req_phys;
382*c95a3ae2Sjmcneill 	args[2] = req_len;
383*c95a3ae2Sjmcneill 	args[3] = rsp_phys;
384*c95a3ae2Sjmcneill 	args[4] = rsp_len;
385*c95a3ae2Sjmcneill 
386*c95a3ae2Sjmcneill 	/* Make call into TEE */
387*c95a3ae2Sjmcneill 	ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_TZ_APPS,
388*c95a3ae2Sjmcneill 	    QCTEE_TZ_SVC_APP_ID_PLACEHOLDER, 0x01,
389*c95a3ae2Sjmcneill 	    arginfo, args, __arraycount(args), res);
390*c95a3ae2Sjmcneill 
391*c95a3ae2Sjmcneill 	/* If the call succeeded, check the response status */
392*c95a3ae2Sjmcneill 	if (ret == 0)
393*c95a3ae2Sjmcneill 		ret = res[0];
394*c95a3ae2Sjmcneill 
395*c95a3ae2Sjmcneill 	return ret;
396*c95a3ae2Sjmcneill }
397*c95a3ae2Sjmcneill 
398*c95a3ae2Sjmcneill struct qcscm_req_uefi_get_variable {
399*c95a3ae2Sjmcneill 	uint32_t command_id;
400*c95a3ae2Sjmcneill 	uint32_t length;
401*c95a3ae2Sjmcneill 	uint32_t name_offset;
402*c95a3ae2Sjmcneill 	uint32_t name_size;
403*c95a3ae2Sjmcneill 	uint32_t guid_offset;
404*c95a3ae2Sjmcneill 	uint32_t guid_size;
405*c95a3ae2Sjmcneill 	uint32_t data_size;
406*c95a3ae2Sjmcneill };
407*c95a3ae2Sjmcneill 
408*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_get_variable {
409*c95a3ae2Sjmcneill 	uint32_t command_id;
410*c95a3ae2Sjmcneill 	uint32_t length;
411*c95a3ae2Sjmcneill 	uint32_t status;
412*c95a3ae2Sjmcneill 	uint32_t attributes;
413*c95a3ae2Sjmcneill 	uint32_t data_offset;
414*c95a3ae2Sjmcneill 	uint32_t data_size;
415*c95a3ae2Sjmcneill };
416*c95a3ae2Sjmcneill 
417*c95a3ae2Sjmcneill efi_status
418*c95a3ae2Sjmcneill qcscm_uefi_get_variable(struct qcscm_softc *sc,
419*c95a3ae2Sjmcneill     efi_char *name, int name_size, struct uuid *guid,
420*c95a3ae2Sjmcneill     uint32_t *attributes, uint8_t *data, int *data_size)
421*c95a3ae2Sjmcneill {
422*c95a3ae2Sjmcneill 	struct qcscm_req_uefi_get_variable *req;
423*c95a3ae2Sjmcneill 	struct qcscm_rsp_uefi_get_variable *resp;
424*c95a3ae2Sjmcneill 	struct qcscm_dmamem *qdm;
425*c95a3ae2Sjmcneill 	size_t reqsize, respsize;
426*c95a3ae2Sjmcneill 	off_t reqoff, respoff;
427*c95a3ae2Sjmcneill 	int ret;
428*c95a3ae2Sjmcneill 
429*c95a3ae2Sjmcneill 	if (sc->sc_uefi_id == UINT32_MAX)
430*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
431*c95a3ae2Sjmcneill 
432*c95a3ae2Sjmcneill 	reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid));
433*c95a3ae2Sjmcneill 	respsize = ALIGN(sizeof(*resp)) + ALIGN(*data_size);
434*c95a3ae2Sjmcneill 
435*c95a3ae2Sjmcneill 	reqoff = 0;
436*c95a3ae2Sjmcneill 	respoff = reqsize;
437*c95a3ae2Sjmcneill 
438*c95a3ae2Sjmcneill 	qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8);
439*c95a3ae2Sjmcneill 	if (qdm == NULL)
440*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
441*c95a3ae2Sjmcneill 
442*c95a3ae2Sjmcneill 	req = QCSCM_DMA_KVA(qdm, reqoff);
443*c95a3ae2Sjmcneill 	req->command_id = QCTEE_UEFI_GET_VARIABLE;
444*c95a3ae2Sjmcneill 	req->data_size = *data_size;
445*c95a3ae2Sjmcneill 	req->name_offset = ALIGN(sizeof(*req));
446*c95a3ae2Sjmcneill 	req->name_size = name_size;
447*c95a3ae2Sjmcneill 	req->guid_offset = ALIGN(req->name_offset + req->name_size);
448*c95a3ae2Sjmcneill 	req->guid_size = sizeof(*guid);
449*c95a3ae2Sjmcneill 	req->length = req->guid_offset + req->guid_size;
450*c95a3ae2Sjmcneill 
451*c95a3ae2Sjmcneill 	memcpy((char *)req + req->guid_offset, guid, sizeof(*guid));
452*c95a3ae2Sjmcneill 	memcpy((char *)req + req->name_offset, name, name_size);
453*c95a3ae2Sjmcneill 
454*c95a3ae2Sjmcneill 	cpu_drain_writebuf();
455*c95a3ae2Sjmcneill 
456*c95a3ae2Sjmcneill 	ret = qcscm_tee_app_send(sc, sc->sc_uefi_id,
457*c95a3ae2Sjmcneill 	    QCSCM_DMA_DVA(qdm) + reqoff, reqsize,
458*c95a3ae2Sjmcneill 	    QCSCM_DMA_DVA(qdm) + respoff, respsize);
459*c95a3ae2Sjmcneill 	if (ret) {
460*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
461*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
462*c95a3ae2Sjmcneill 	}
463*c95a3ae2Sjmcneill 
464*c95a3ae2Sjmcneill 	cpu_drain_writebuf();
465*c95a3ae2Sjmcneill 
466*c95a3ae2Sjmcneill 	resp = QCSCM_DMA_KVA(qdm, respoff);
467*c95a3ae2Sjmcneill 	if (resp->command_id != QCTEE_UEFI_GET_VARIABLE ||
468*c95a3ae2Sjmcneill 	    resp->length < sizeof(*resp)) {
469*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
470*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
471*c95a3ae2Sjmcneill 	}
472*c95a3ae2Sjmcneill 
473*c95a3ae2Sjmcneill 	if (resp->status) {
474*c95a3ae2Sjmcneill 		if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL)
475*c95a3ae2Sjmcneill 			*data_size = resp->data_size;
476*c95a3ae2Sjmcneill 		if (attributes)
477*c95a3ae2Sjmcneill 			*attributes = resp->attributes;
478*c95a3ae2Sjmcneill 		ret = resp->status;
479*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
480*c95a3ae2Sjmcneill 		return ret;
481*c95a3ae2Sjmcneill 	}
482*c95a3ae2Sjmcneill 
483*c95a3ae2Sjmcneill 	if (resp->length > respsize ||
484*c95a3ae2Sjmcneill 	    resp->data_offset + resp->data_size > resp->length) {
485*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
486*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
487*c95a3ae2Sjmcneill 	}
488*c95a3ae2Sjmcneill 
489*c95a3ae2Sjmcneill 	if (attributes)
490*c95a3ae2Sjmcneill 		*attributes = resp->attributes;
491*c95a3ae2Sjmcneill 
492*c95a3ae2Sjmcneill 	if (*data_size == 0) {
493*c95a3ae2Sjmcneill 		*data_size = resp->data_size;
494*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
495*c95a3ae2Sjmcneill 		return QCTEE_UEFI_SUCCESS;
496*c95a3ae2Sjmcneill 	}
497*c95a3ae2Sjmcneill 
498*c95a3ae2Sjmcneill 	if (resp->data_size > *data_size) {
499*c95a3ae2Sjmcneill 		*data_size = resp->data_size;
500*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
501*c95a3ae2Sjmcneill 		return QCTEE_UEFI_BUFFER_TOO_SMALL;
502*c95a3ae2Sjmcneill 	}
503*c95a3ae2Sjmcneill 
504*c95a3ae2Sjmcneill 	memcpy(data, (char *)resp + resp->data_offset, resp->data_size);
505*c95a3ae2Sjmcneill 	*data_size = resp->data_size;
506*c95a3ae2Sjmcneill 
507*c95a3ae2Sjmcneill 	qcscm_dmamem_free(sc, qdm);
508*c95a3ae2Sjmcneill 	return EFI_SUCCESS;
509*c95a3ae2Sjmcneill }
510*c95a3ae2Sjmcneill 
511*c95a3ae2Sjmcneill struct qcscm_req_uefi_set_variable {
512*c95a3ae2Sjmcneill 	uint32_t command_id;
513*c95a3ae2Sjmcneill 	uint32_t length;
514*c95a3ae2Sjmcneill 	uint32_t name_offset;
515*c95a3ae2Sjmcneill 	uint32_t name_size;
516*c95a3ae2Sjmcneill 	uint32_t guid_offset;
517*c95a3ae2Sjmcneill 	uint32_t guid_size;
518*c95a3ae2Sjmcneill 	uint32_t attributes;
519*c95a3ae2Sjmcneill 	uint32_t data_offset;
520*c95a3ae2Sjmcneill 	uint32_t data_size;
521*c95a3ae2Sjmcneill };
522*c95a3ae2Sjmcneill 
523*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_set_variable {
524*c95a3ae2Sjmcneill 	uint32_t command_id;
525*c95a3ae2Sjmcneill 	uint32_t length;
526*c95a3ae2Sjmcneill 	uint32_t status;
527*c95a3ae2Sjmcneill 	uint32_t unknown[2];
528*c95a3ae2Sjmcneill };
529*c95a3ae2Sjmcneill 
530*c95a3ae2Sjmcneill efi_status
531*c95a3ae2Sjmcneill qcscm_uefi_set_variable(struct qcscm_softc *sc,
532*c95a3ae2Sjmcneill     efi_char *name, int name_size, struct uuid *guid,
533*c95a3ae2Sjmcneill     uint32_t attributes, uint8_t *data, int data_size)
534*c95a3ae2Sjmcneill {
535*c95a3ae2Sjmcneill 	struct qcscm_req_uefi_set_variable *req;
536*c95a3ae2Sjmcneill 	struct qcscm_rsp_uefi_set_variable *resp;
537*c95a3ae2Sjmcneill 	struct qcscm_dmamem *qdm;
538*c95a3ae2Sjmcneill 	size_t reqsize, respsize;
539*c95a3ae2Sjmcneill 	off_t reqoff, respoff;
540*c95a3ae2Sjmcneill 	int ret;
541*c95a3ae2Sjmcneill 
542*c95a3ae2Sjmcneill 	if (sc->sc_uefi_id == UINT32_MAX)
543*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
544*c95a3ae2Sjmcneill 
545*c95a3ae2Sjmcneill 	reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)) +
546*c95a3ae2Sjmcneill 	    ALIGN(data_size);
547*c95a3ae2Sjmcneill 	respsize = ALIGN(sizeof(*resp));
548*c95a3ae2Sjmcneill 
549*c95a3ae2Sjmcneill 	reqoff = 0;
550*c95a3ae2Sjmcneill 	respoff = reqsize;
551*c95a3ae2Sjmcneill 
552*c95a3ae2Sjmcneill 	qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8);
553*c95a3ae2Sjmcneill 	if (qdm == NULL)
554*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
555*c95a3ae2Sjmcneill 
556*c95a3ae2Sjmcneill 	req = QCSCM_DMA_KVA(qdm, reqoff);
557*c95a3ae2Sjmcneill 	req->command_id = QCTEE_UEFI_SET_VARIABLE;
558*c95a3ae2Sjmcneill 	req->attributes = attributes;
559*c95a3ae2Sjmcneill 	req->name_offset = ALIGN(sizeof(*req));
560*c95a3ae2Sjmcneill 	req->name_size = name_size;
561*c95a3ae2Sjmcneill 	req->guid_offset = ALIGN(req->name_offset + req->name_size);
562*c95a3ae2Sjmcneill 	req->guid_size = sizeof(*guid);
563*c95a3ae2Sjmcneill 	req->data_offset = ALIGN(req->guid_offset + req->guid_size);
564*c95a3ae2Sjmcneill 	req->data_size = data_size;
565*c95a3ae2Sjmcneill 	req->length = req->data_offset + req->data_size;
566*c95a3ae2Sjmcneill 
567*c95a3ae2Sjmcneill 	memcpy((char *)req + req->name_offset, name, name_size);
568*c95a3ae2Sjmcneill 	memcpy((char *)req + req->guid_offset, guid, sizeof(*guid));
569*c95a3ae2Sjmcneill 	memcpy((char *)req + req->data_offset, data, data_size);
570*c95a3ae2Sjmcneill 
571*c95a3ae2Sjmcneill 	ret = qcscm_tee_app_send(sc, sc->sc_uefi_id,
572*c95a3ae2Sjmcneill 	    QCSCM_DMA_DVA(qdm) + reqoff, reqsize,
573*c95a3ae2Sjmcneill 	    QCSCM_DMA_DVA(qdm) + respoff, respsize);
574*c95a3ae2Sjmcneill 	if (ret) {
575*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
576*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
577*c95a3ae2Sjmcneill 	}
578*c95a3ae2Sjmcneill 
579*c95a3ae2Sjmcneill 	resp = QCSCM_DMA_KVA(qdm, respoff);
580*c95a3ae2Sjmcneill 	if (resp->command_id != QCTEE_UEFI_SET_VARIABLE ||
581*c95a3ae2Sjmcneill 	    resp->length < sizeof(*resp) || resp->length > respsize) {
582*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
583*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
584*c95a3ae2Sjmcneill 	}
585*c95a3ae2Sjmcneill 
586*c95a3ae2Sjmcneill 	if (resp->status) {
587*c95a3ae2Sjmcneill 		ret = resp->status;
588*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
589*c95a3ae2Sjmcneill 		return ret;
590*c95a3ae2Sjmcneill 	}
591*c95a3ae2Sjmcneill 
592*c95a3ae2Sjmcneill 	qcscm_dmamem_free(sc, qdm);
593*c95a3ae2Sjmcneill 	return QCTEE_UEFI_SUCCESS;
594*c95a3ae2Sjmcneill }
595*c95a3ae2Sjmcneill 
596*c95a3ae2Sjmcneill struct qcscm_req_uefi_get_next_variable {
597*c95a3ae2Sjmcneill 	uint32_t command_id;
598*c95a3ae2Sjmcneill 	uint32_t length;
599*c95a3ae2Sjmcneill 	uint32_t guid_offset;
600*c95a3ae2Sjmcneill 	uint32_t guid_size;
601*c95a3ae2Sjmcneill 	uint32_t name_offset;
602*c95a3ae2Sjmcneill 	uint32_t name_size;
603*c95a3ae2Sjmcneill };
604*c95a3ae2Sjmcneill 
605*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_get_next_variable {
606*c95a3ae2Sjmcneill 	uint32_t command_id;
607*c95a3ae2Sjmcneill 	uint32_t length;
608*c95a3ae2Sjmcneill 	uint32_t status;
609*c95a3ae2Sjmcneill 	uint32_t guid_offset;
610*c95a3ae2Sjmcneill 	uint32_t guid_size;
611*c95a3ae2Sjmcneill 	uint32_t name_offset;
612*c95a3ae2Sjmcneill 	uint32_t name_size;
613*c95a3ae2Sjmcneill };
614*c95a3ae2Sjmcneill 
615*c95a3ae2Sjmcneill efi_status
616*c95a3ae2Sjmcneill qcscm_uefi_get_next_variable(struct qcscm_softc *sc,
617*c95a3ae2Sjmcneill     efi_char *name, int *name_size, struct uuid *guid)
618*c95a3ae2Sjmcneill {
619*c95a3ae2Sjmcneill 	struct qcscm_req_uefi_get_next_variable *req;
620*c95a3ae2Sjmcneill 	struct qcscm_rsp_uefi_get_next_variable *resp;
621*c95a3ae2Sjmcneill 	struct qcscm_dmamem *qdm;
622*c95a3ae2Sjmcneill 	size_t reqsize, respsize;
623*c95a3ae2Sjmcneill 	off_t reqoff, respoff;
624*c95a3ae2Sjmcneill 	int ret;
625*c95a3ae2Sjmcneill 
626*c95a3ae2Sjmcneill 	if (sc->sc_uefi_id == UINT32_MAX)
627*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
628*c95a3ae2Sjmcneill 
629*c95a3ae2Sjmcneill 	reqsize = ALIGN(sizeof(*req)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size);
630*c95a3ae2Sjmcneill 	respsize = ALIGN(sizeof(*resp)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size);
631*c95a3ae2Sjmcneill 
632*c95a3ae2Sjmcneill 	reqoff = 0;
633*c95a3ae2Sjmcneill 	respoff = reqsize;
634*c95a3ae2Sjmcneill 
635*c95a3ae2Sjmcneill 	qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8);
636*c95a3ae2Sjmcneill 	if (qdm == NULL)
637*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
638*c95a3ae2Sjmcneill 
639*c95a3ae2Sjmcneill 	req = QCSCM_DMA_KVA(qdm, reqoff);
640*c95a3ae2Sjmcneill 	req->command_id = QCTEE_UEFI_GET_NEXT_VARIABLE;
641*c95a3ae2Sjmcneill 	req->guid_offset = ALIGN(sizeof(*req));
642*c95a3ae2Sjmcneill 	req->guid_size = sizeof(*guid);
643*c95a3ae2Sjmcneill 	req->name_offset = ALIGN(req->guid_offset + req->guid_size);
644*c95a3ae2Sjmcneill 	req->name_size = *name_size;
645*c95a3ae2Sjmcneill 	req->length = req->name_offset + req->name_size;
646*c95a3ae2Sjmcneill 
647*c95a3ae2Sjmcneill 	memcpy((char *)req + req->guid_offset, guid, sizeof(*guid));
648*c95a3ae2Sjmcneill 	memcpy((char *)req + req->name_offset, name, *name_size);
649*c95a3ae2Sjmcneill 
650*c95a3ae2Sjmcneill 	ret = qcscm_tee_app_send(sc, sc->sc_uefi_id,
651*c95a3ae2Sjmcneill 	    QCSCM_DMA_DVA(qdm) + reqoff, reqsize,
652*c95a3ae2Sjmcneill 	    QCSCM_DMA_DVA(qdm) + respoff, respsize);
653*c95a3ae2Sjmcneill 	if (ret) {
654*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
655*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
656*c95a3ae2Sjmcneill 	}
657*c95a3ae2Sjmcneill 
658*c95a3ae2Sjmcneill 	resp = QCSCM_DMA_KVA(qdm, respoff);
659*c95a3ae2Sjmcneill 	if (resp->command_id != QCTEE_UEFI_GET_NEXT_VARIABLE ||
660*c95a3ae2Sjmcneill 	    resp->length < sizeof(*resp) || resp->length > respsize) {
661*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
662*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
663*c95a3ae2Sjmcneill 	}
664*c95a3ae2Sjmcneill 
665*c95a3ae2Sjmcneill 	if (resp->status) {
666*c95a3ae2Sjmcneill 		if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL)
667*c95a3ae2Sjmcneill 			*name_size = resp->name_size;
668*c95a3ae2Sjmcneill 		ret = resp->status;
669*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
670*c95a3ae2Sjmcneill 		return ret;
671*c95a3ae2Sjmcneill 	}
672*c95a3ae2Sjmcneill 
673*c95a3ae2Sjmcneill 	if (resp->guid_offset + resp->guid_size > resp->length ||
674*c95a3ae2Sjmcneill 	    resp->name_offset + resp->name_size > resp->length) {
675*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
676*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
677*c95a3ae2Sjmcneill 	}
678*c95a3ae2Sjmcneill 
679*c95a3ae2Sjmcneill 	if (resp->guid_size != sizeof(*guid)) {
680*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
681*c95a3ae2Sjmcneill 		return QCTEE_UEFI_DEVICE_ERROR;
682*c95a3ae2Sjmcneill 	}
683*c95a3ae2Sjmcneill 
684*c95a3ae2Sjmcneill 	if (resp->name_size > *name_size) {
685*c95a3ae2Sjmcneill 		*name_size = resp->name_size;
686*c95a3ae2Sjmcneill 		qcscm_dmamem_free(sc, qdm);
687*c95a3ae2Sjmcneill 		return QCTEE_UEFI_BUFFER_TOO_SMALL;
688*c95a3ae2Sjmcneill 	}
689*c95a3ae2Sjmcneill 
690*c95a3ae2Sjmcneill 	memcpy(guid, (char *)resp + resp->guid_offset, sizeof(*guid));
691*c95a3ae2Sjmcneill 	memcpy(name, (char *)resp + resp->name_offset, resp->name_size);
692*c95a3ae2Sjmcneill 	*name_size = resp->name_size;
693*c95a3ae2Sjmcneill 
694*c95a3ae2Sjmcneill 	qcscm_dmamem_free(sc, qdm);
695*c95a3ae2Sjmcneill 	return QCTEE_UEFI_SUCCESS;
696*c95a3ae2Sjmcneill }
697*c95a3ae2Sjmcneill 
698*c95a3ae2Sjmcneill efi_status
699*c95a3ae2Sjmcneill qcscm_efi_get_variable(efi_char *name, struct uuid *guid, uint32_t *attributes,
700*c95a3ae2Sjmcneill    u_long *data_size, void *data)
701*c95a3ae2Sjmcneill {
702*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
703*c95a3ae2Sjmcneill 	efi_status status;
704*c95a3ae2Sjmcneill 	int name_size;
705*c95a3ae2Sjmcneill 	int size;
706*c95a3ae2Sjmcneill 
707*c95a3ae2Sjmcneill 	name_size = 0;
708*c95a3ae2Sjmcneill 	while (name[name_size])
709*c95a3ae2Sjmcneill 		name_size++;
710*c95a3ae2Sjmcneill 	name_size++;
711*c95a3ae2Sjmcneill 
712*c95a3ae2Sjmcneill 	size = *data_size;
713*c95a3ae2Sjmcneill 	status = qcscm_uefi_get_variable(sc, name, name_size * 2, guid,
714*c95a3ae2Sjmcneill 	    attributes, data, &size);
715*c95a3ae2Sjmcneill 	*data_size = size;
716*c95a3ae2Sjmcneill 
717*c95a3ae2Sjmcneill 	/* Convert 32-bit status code to 64-bit. */
718*c95a3ae2Sjmcneill 	return ((status & 0xf0000000) << 32 | (status & 0x0fffffff));
719*c95a3ae2Sjmcneill }
720*c95a3ae2Sjmcneill 
721*c95a3ae2Sjmcneill efi_status
722*c95a3ae2Sjmcneill qcscm_efi_set_variable(efi_char *name, struct uuid *guid, uint32_t attributes,
723*c95a3ae2Sjmcneill     u_long data_size, void *data)
724*c95a3ae2Sjmcneill {
725*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
726*c95a3ae2Sjmcneill 	efi_status status;
727*c95a3ae2Sjmcneill 	int name_size;
728*c95a3ae2Sjmcneill 
729*c95a3ae2Sjmcneill 	name_size = 0;
730*c95a3ae2Sjmcneill 	while (name[name_size])
731*c95a3ae2Sjmcneill 		name_size++;
732*c95a3ae2Sjmcneill 	name_size++;
733*c95a3ae2Sjmcneill 
734*c95a3ae2Sjmcneill 	status = qcscm_uefi_set_variable(sc, name, name_size * 2, guid,
735*c95a3ae2Sjmcneill 	    attributes, data, data_size);
736*c95a3ae2Sjmcneill 
737*c95a3ae2Sjmcneill 	/* Convert 32-bit status code to 64-bit. */
738*c95a3ae2Sjmcneill 	return ((status & 0xf0000000) << 32 | (status & 0x0fffffff));
739*c95a3ae2Sjmcneill }
740*c95a3ae2Sjmcneill 
741*c95a3ae2Sjmcneill efi_status
742*c95a3ae2Sjmcneill qcscm_efi_get_next_variable_name(u_long *name_size, efi_char *name,
743*c95a3ae2Sjmcneill     struct uuid *guid)
744*c95a3ae2Sjmcneill {
745*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
746*c95a3ae2Sjmcneill 	efi_status status;
747*c95a3ae2Sjmcneill 	int size;
748*c95a3ae2Sjmcneill 
749*c95a3ae2Sjmcneill 	size = *name_size;
750*c95a3ae2Sjmcneill 	status = qcscm_uefi_get_next_variable(sc, name, &size, guid);
751*c95a3ae2Sjmcneill 	*name_size = size;
752*c95a3ae2Sjmcneill 
753*c95a3ae2Sjmcneill 	/* Convert 32-bit status code to 64-bit. */
754*c95a3ae2Sjmcneill 	return ((status & 0xf0000000) << 32 | (status & 0x0fffffff));
755*c95a3ae2Sjmcneill }
756*c95a3ae2Sjmcneill 
757*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG
758*c95a3ae2Sjmcneill 
759*c95a3ae2Sjmcneill void
760*c95a3ae2Sjmcneill qcscm_uefi_dump_variables(struct qcscm_softc *sc)
761*c95a3ae2Sjmcneill {
762*c95a3ae2Sjmcneill 	efi_char name[128];
763*c95a3ae2Sjmcneill 	struct uuid guid;
764*c95a3ae2Sjmcneill 	int namesize = sizeof(name);
765*c95a3ae2Sjmcneill 	int i, ret;
766*c95a3ae2Sjmcneill 
767*c95a3ae2Sjmcneill 	memset(name, 0, sizeof(name));
768*c95a3ae2Sjmcneill 	memset(&guid, 0, sizeof(guid));
769*c95a3ae2Sjmcneill 
770*c95a3ae2Sjmcneill 	for (;;) {
771*c95a3ae2Sjmcneill 		ret = qcscm_uefi_get_next_variable(sc, name, &namesize, &guid);
772*c95a3ae2Sjmcneill 		if (ret == 0) {
773*c95a3ae2Sjmcneill 			printf("%s: ", device_xname(sc->sc_dev));
774*c95a3ae2Sjmcneill 			for (i = 0; i < namesize / 2; i++)
775*c95a3ae2Sjmcneill 				printf("%c", name[i]);
776*c95a3ae2Sjmcneill 			printf(" { 0x%08x, 0x%04x, 0x%04x, { ",
777*c95a3ae2Sjmcneill 			   guid.time_low, guid.time_mid, guid.time_hi_and_version);
778*c95a3ae2Sjmcneill 			printf(" 0x%02x, 0x%02x,",
779*c95a3ae2Sjmcneill 			   guid.clock_seq_hi_and_reserved,
780*c95a3ae2Sjmcneill 			   guid.clock_seq_low);
781*c95a3ae2Sjmcneill 			for (i = 0; i < 6; i++) {
782*c95a3ae2Sjmcneill 				printf(" 0x%02x,", guid.node[i]);
783*c95a3ae2Sjmcneill 			}
784*c95a3ae2Sjmcneill 			printf(" }");
785*c95a3ae2Sjmcneill 			printf("\n");
786*c95a3ae2Sjmcneill 			namesize = sizeof(name);
787*c95a3ae2Sjmcneill 			continue;
788*c95a3ae2Sjmcneill 		}
789*c95a3ae2Sjmcneill 		break;
790*c95a3ae2Sjmcneill 	}
791*c95a3ae2Sjmcneill }
792*c95a3ae2Sjmcneill 
793*c95a3ae2Sjmcneill void
794*c95a3ae2Sjmcneill qcscm_uefi_dump_variable(struct qcscm_softc *sc, efi_char *name, int namesize,
795*c95a3ae2Sjmcneill     struct uuid *guid)
796*c95a3ae2Sjmcneill {
797*c95a3ae2Sjmcneill 	uint8_t data[512];
798*c95a3ae2Sjmcneill 	int datasize = sizeof(data);
799*c95a3ae2Sjmcneill 	int i, ret;
800*c95a3ae2Sjmcneill 
801*c95a3ae2Sjmcneill 	ret = qcscm_uefi_get_variable(sc, name, namesize, guid,
802*c95a3ae2Sjmcneill 	    NULL, data, &datasize);
803*c95a3ae2Sjmcneill 	if (ret != QCTEE_UEFI_SUCCESS) {
804*c95a3ae2Sjmcneill 		printf("%s: error reading ", device_xname(sc->sc_dev));
805*c95a3ae2Sjmcneill 		for (i = 0; i < namesize / 2; i++)
806*c95a3ae2Sjmcneill 			printf("%c", name[i]);
807*c95a3ae2Sjmcneill 		printf("\n");
808*c95a3ae2Sjmcneill 		return;
809*c95a3ae2Sjmcneill 	}
810*c95a3ae2Sjmcneill 
811*c95a3ae2Sjmcneill 	printf("%s: ", device_xname(sc->sc_dev));
812*c95a3ae2Sjmcneill 	for (i = 0; i < namesize / 2; i++)
813*c95a3ae2Sjmcneill 		printf("%c", name[i]);
814*c95a3ae2Sjmcneill 	printf(" = ");
815*c95a3ae2Sjmcneill 	for (i = 0; i < datasize; i++)
816*c95a3ae2Sjmcneill 		printf("%02x", data[i]);
817*c95a3ae2Sjmcneill 	printf("\n");
818*c95a3ae2Sjmcneill }
819*c95a3ae2Sjmcneill 
820*c95a3ae2Sjmcneill #endif
821*c95a3ae2Sjmcneill 
822*c95a3ae2Sjmcneill int
823*c95a3ae2Sjmcneill qcscm_uefi_rtc_get(uint32_t *off)
824*c95a3ae2Sjmcneill {
825*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
826*c95a3ae2Sjmcneill 	uint32_t rtcinfo[3];
827*c95a3ae2Sjmcneill 	int rtcinfosize = sizeof(rtcinfo);
828*c95a3ae2Sjmcneill 
829*c95a3ae2Sjmcneill 	if (sc == NULL)
830*c95a3ae2Sjmcneill 		return ENXIO;
831*c95a3ae2Sjmcneill 
832*c95a3ae2Sjmcneill 	if (qcscm_uefi_get_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO),
833*c95a3ae2Sjmcneill 	    &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo,
834*c95a3ae2Sjmcneill 	    &rtcinfosize) != 0)
835*c95a3ae2Sjmcneill 		return EIO;
836*c95a3ae2Sjmcneill 
837*c95a3ae2Sjmcneill 	/* UEFI stores the offset based on GPS epoch */
838*c95a3ae2Sjmcneill 	*off = rtcinfo[0] + UNIX_GPS_EPOCH_OFFSET;
839*c95a3ae2Sjmcneill 	return 0;
840*c95a3ae2Sjmcneill }
841*c95a3ae2Sjmcneill 
842*c95a3ae2Sjmcneill int
843*c95a3ae2Sjmcneill qcscm_uefi_rtc_set(uint32_t off)
844*c95a3ae2Sjmcneill {
845*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
846*c95a3ae2Sjmcneill 	uint32_t rtcinfo[3];
847*c95a3ae2Sjmcneill 	int rtcinfosize = sizeof(rtcinfo);
848*c95a3ae2Sjmcneill 
849*c95a3ae2Sjmcneill 	if (sc == NULL)
850*c95a3ae2Sjmcneill 		return ENXIO;
851*c95a3ae2Sjmcneill 
852*c95a3ae2Sjmcneill 	if (qcscm_uefi_get_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO),
853*c95a3ae2Sjmcneill 	    &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo,
854*c95a3ae2Sjmcneill 	    &rtcinfosize) != 0)
855*c95a3ae2Sjmcneill 		return EIO;
856*c95a3ae2Sjmcneill 
857*c95a3ae2Sjmcneill 	/* UEFI stores the offset based on GPS epoch */
858*c95a3ae2Sjmcneill 	off -= UNIX_GPS_EPOCH_OFFSET;
859*c95a3ae2Sjmcneill 
860*c95a3ae2Sjmcneill 	/* No need to set if we're not changing anything */
861*c95a3ae2Sjmcneill 	if (rtcinfo[0] == off)
862*c95a3ae2Sjmcneill 		return 0;
863*c95a3ae2Sjmcneill 
864*c95a3ae2Sjmcneill 	rtcinfo[0] = off;
865*c95a3ae2Sjmcneill 
866*c95a3ae2Sjmcneill 	if (qcscm_uefi_set_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO),
867*c95a3ae2Sjmcneill 	    &qcscm_uefi_rtcinfo_guid, EFI_VARIABLE_NON_VOLATILE |
868*c95a3ae2Sjmcneill 	    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
869*c95a3ae2Sjmcneill 	    (uint8_t *)rtcinfo, sizeof(rtcinfo)) != 0)
870*c95a3ae2Sjmcneill 		return EIO;
871*c95a3ae2Sjmcneill 
872*c95a3ae2Sjmcneill 	return 0;
873*c95a3ae2Sjmcneill }
874*c95a3ae2Sjmcneill 
875*c95a3ae2Sjmcneill int
876*c95a3ae2Sjmcneill qcscm_pas_init_image(uint32_t peripheral, paddr_t metadata)
877*c95a3ae2Sjmcneill {
878*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
879*c95a3ae2Sjmcneill 	uint64_t res[3];
880*c95a3ae2Sjmcneill 	uint64_t args[2];
881*c95a3ae2Sjmcneill 	uint32_t arginfo;
882*c95a3ae2Sjmcneill 	int ret;
883*c95a3ae2Sjmcneill 
884*c95a3ae2Sjmcneill 	if (sc == NULL)
885*c95a3ae2Sjmcneill 		return ENXIO;
886*c95a3ae2Sjmcneill 
887*c95a3ae2Sjmcneill 	arginfo = QCSCM_ARGINFO_NUM(__arraycount(args));
888*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL);
889*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW);
890*c95a3ae2Sjmcneill 	args[0] = peripheral;
891*c95a3ae2Sjmcneill 	args[1] = metadata;
892*c95a3ae2Sjmcneill 
893*c95a3ae2Sjmcneill 	/* Make call into TEE */
894*c95a3ae2Sjmcneill 	ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL,
895*c95a3ae2Sjmcneill 	    QCSCM_PIL_PAS_INIT_IMAGE, arginfo, args, __arraycount(args), res);
896*c95a3ae2Sjmcneill 
897*c95a3ae2Sjmcneill 	/* If the call succeeded, check the response status */
898*c95a3ae2Sjmcneill 	if (ret == 0)
899*c95a3ae2Sjmcneill 		ret = res[0];
900*c95a3ae2Sjmcneill 
901*c95a3ae2Sjmcneill 	return ret;
902*c95a3ae2Sjmcneill }
903*c95a3ae2Sjmcneill 
904*c95a3ae2Sjmcneill int
905*c95a3ae2Sjmcneill qcscm_pas_mem_setup(uint32_t peripheral, paddr_t addr, size_t size)
906*c95a3ae2Sjmcneill {
907*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
908*c95a3ae2Sjmcneill 	uint64_t res[3];
909*c95a3ae2Sjmcneill 	uint64_t args[3];
910*c95a3ae2Sjmcneill 	uint32_t arginfo;
911*c95a3ae2Sjmcneill 	int ret;
912*c95a3ae2Sjmcneill 
913*c95a3ae2Sjmcneill 	if (sc == NULL)
914*c95a3ae2Sjmcneill 		return ENXIO;
915*c95a3ae2Sjmcneill 
916*c95a3ae2Sjmcneill 	arginfo = QCSCM_ARGINFO_NUM(__arraycount(args));
917*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL);
918*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL);
919*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL);
920*c95a3ae2Sjmcneill 	args[0] = peripheral;
921*c95a3ae2Sjmcneill 	args[1] = addr;
922*c95a3ae2Sjmcneill 	args[2] = size;
923*c95a3ae2Sjmcneill 
924*c95a3ae2Sjmcneill 	/* Make call into TEE */
925*c95a3ae2Sjmcneill 	ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL,
926*c95a3ae2Sjmcneill 	    QCSCM_PIL_PAS_MEM_SETUP, arginfo, args, __arraycount(args), res);
927*c95a3ae2Sjmcneill 
928*c95a3ae2Sjmcneill 	/* If the call succeeded, check the response status */
929*c95a3ae2Sjmcneill 	if (ret == 0)
930*c95a3ae2Sjmcneill 		ret = res[0];
931*c95a3ae2Sjmcneill 
932*c95a3ae2Sjmcneill 	return ret;
933*c95a3ae2Sjmcneill }
934*c95a3ae2Sjmcneill 
935*c95a3ae2Sjmcneill int
936*c95a3ae2Sjmcneill qcscm_pas_auth_and_reset(uint32_t peripheral)
937*c95a3ae2Sjmcneill {
938*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
939*c95a3ae2Sjmcneill 	uint64_t res[3];
940*c95a3ae2Sjmcneill 	uint64_t args[1];
941*c95a3ae2Sjmcneill 	uint32_t arginfo;
942*c95a3ae2Sjmcneill 	int ret;
943*c95a3ae2Sjmcneill 
944*c95a3ae2Sjmcneill 	if (sc == NULL)
945*c95a3ae2Sjmcneill 		return ENXIO;
946*c95a3ae2Sjmcneill 
947*c95a3ae2Sjmcneill 	arginfo = QCSCM_ARGINFO_NUM(__arraycount(args));
948*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL);
949*c95a3ae2Sjmcneill 	args[0] = peripheral;
950*c95a3ae2Sjmcneill 
951*c95a3ae2Sjmcneill 	/* Make call into TEE */
952*c95a3ae2Sjmcneill 	ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL,
953*c95a3ae2Sjmcneill 	    QCSCM_PIL_PAS_AUTH_AND_RESET, arginfo, args, __arraycount(args), res);
954*c95a3ae2Sjmcneill 
955*c95a3ae2Sjmcneill 	/* If the call succeeded, check the response status */
956*c95a3ae2Sjmcneill 	if (ret == 0)
957*c95a3ae2Sjmcneill 		ret = res[0];
958*c95a3ae2Sjmcneill 
959*c95a3ae2Sjmcneill 	return ret;
960*c95a3ae2Sjmcneill }
961*c95a3ae2Sjmcneill 
962*c95a3ae2Sjmcneill int
963*c95a3ae2Sjmcneill qcscm_pas_shutdown(uint32_t peripheral)
964*c95a3ae2Sjmcneill {
965*c95a3ae2Sjmcneill 	struct qcscm_softc *sc = qcscm_sc;
966*c95a3ae2Sjmcneill 	uint64_t res[3];
967*c95a3ae2Sjmcneill 	uint64_t args[1];
968*c95a3ae2Sjmcneill 	uint32_t arginfo;
969*c95a3ae2Sjmcneill 	int ret;
970*c95a3ae2Sjmcneill 
971*c95a3ae2Sjmcneill 	if (sc == NULL)
972*c95a3ae2Sjmcneill 		return ENXIO;
973*c95a3ae2Sjmcneill 
974*c95a3ae2Sjmcneill 	arginfo = QCSCM_ARGINFO_NUM(__arraycount(args));
975*c95a3ae2Sjmcneill 	arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL);
976*c95a3ae2Sjmcneill 	args[0] = peripheral;
977*c95a3ae2Sjmcneill 
978*c95a3ae2Sjmcneill 	/* Make call into TEE */
979*c95a3ae2Sjmcneill 	ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL,
980*c95a3ae2Sjmcneill 	    QCSCM_PIL_PAS_SHUTDOWN, arginfo, args, __arraycount(args), res);
981*c95a3ae2Sjmcneill 
982*c95a3ae2Sjmcneill 	/* If the call succeeded, check the response status */
983*c95a3ae2Sjmcneill 	if (ret == 0)
984*c95a3ae2Sjmcneill 		ret = res[0];
985*c95a3ae2Sjmcneill 
986*c95a3ae2Sjmcneill 	return ret;
987*c95a3ae2Sjmcneill }
988*c95a3ae2Sjmcneill 
989*c95a3ae2Sjmcneill /* DMA code */
990*c95a3ae2Sjmcneill struct qcscm_dmamem *
991*c95a3ae2Sjmcneill qcscm_dmamem_alloc(struct qcscm_softc *sc, bus_size_t size, bus_size_t align)
992*c95a3ae2Sjmcneill {
993*c95a3ae2Sjmcneill 	struct qcscm_dmamem *qdm;
994*c95a3ae2Sjmcneill 	int nsegs;
995*c95a3ae2Sjmcneill 
996*c95a3ae2Sjmcneill 	qdm = kmem_zalloc(sizeof(*qdm), KM_SLEEP);
997*c95a3ae2Sjmcneill 	qdm->qdm_size = size;
998*c95a3ae2Sjmcneill 
999*c95a3ae2Sjmcneill 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1000*c95a3ae2Sjmcneill 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &qdm->qdm_map) != 0)
1001*c95a3ae2Sjmcneill 		goto qdmfree;
1002*c95a3ae2Sjmcneill 
1003*c95a3ae2Sjmcneill 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0,
1004*c95a3ae2Sjmcneill 	    &qdm->qdm_seg, 1, &nsegs, BUS_DMA_WAITOK) != 0)
1005*c95a3ae2Sjmcneill 		goto destroy;
1006*c95a3ae2Sjmcneill 
1007*c95a3ae2Sjmcneill 	if (bus_dmamem_map(sc->sc_dmat, &qdm->qdm_seg, nsegs, size,
1008*c95a3ae2Sjmcneill 	    &qdm->qdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
1009*c95a3ae2Sjmcneill 		goto free;
1010*c95a3ae2Sjmcneill 
1011*c95a3ae2Sjmcneill 	if (bus_dmamap_load(sc->sc_dmat, qdm->qdm_map, qdm->qdm_kva, size,
1012*c95a3ae2Sjmcneill 	    NULL, BUS_DMA_WAITOK) != 0)
1013*c95a3ae2Sjmcneill 		goto unmap;
1014*c95a3ae2Sjmcneill 
1015*c95a3ae2Sjmcneill 	memset(qdm->qdm_kva, 0, size);
1016*c95a3ae2Sjmcneill 
1017*c95a3ae2Sjmcneill 	return (qdm);
1018*c95a3ae2Sjmcneill 
1019*c95a3ae2Sjmcneill unmap:
1020*c95a3ae2Sjmcneill 	bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, size);
1021*c95a3ae2Sjmcneill free:
1022*c95a3ae2Sjmcneill 	bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1);
1023*c95a3ae2Sjmcneill destroy:
1024*c95a3ae2Sjmcneill 	bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map);
1025*c95a3ae2Sjmcneill qdmfree:
1026*c95a3ae2Sjmcneill 	kmem_free(qdm, sizeof(*qdm));
1027*c95a3ae2Sjmcneill 
1028*c95a3ae2Sjmcneill 	return (NULL);
1029*c95a3ae2Sjmcneill }
1030*c95a3ae2Sjmcneill 
1031*c95a3ae2Sjmcneill void
1032*c95a3ae2Sjmcneill qcscm_dmamem_free(struct qcscm_softc *sc, struct qcscm_dmamem *qdm)
1033*c95a3ae2Sjmcneill {
1034*c95a3ae2Sjmcneill 	bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, qdm->qdm_size);
1035*c95a3ae2Sjmcneill 	bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1);
1036*c95a3ae2Sjmcneill 	bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map);
1037*c95a3ae2Sjmcneill 	kmem_free(qdm, sizeof(*qdm));
1038*c95a3ae2Sjmcneill }
1039