1*08314e7cSSumit Garg // SPDX-License-Identifier: GPL-2.0
2*08314e7cSSumit Garg /*
3*08314e7cSSumit Garg * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
4*08314e7cSSumit Garg * Copyright (C) 2015 Linaro Ltd.
5*08314e7cSSumit Garg * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
6*08314e7cSSumit Garg */
7*08314e7cSSumit Garg
8*08314e7cSSumit Garg #include <linux/device/devres.h>
9*08314e7cSSumit Garg #include <linux/firmware/qcom/qcom_pas.h>
10*08314e7cSSumit Garg #include <linux/kernel.h>
11*08314e7cSSumit Garg #include <linux/module.h>
12*08314e7cSSumit Garg
13*08314e7cSSumit Garg #include "qcom_pas.h"
14*08314e7cSSumit Garg
15*08314e7cSSumit Garg static struct qcom_pas_ops *ops_ptr;
16*08314e7cSSumit Garg
17*08314e7cSSumit Garg /**
18*08314e7cSSumit Garg * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
19*08314e7cSSumit Garg * context for a given peripheral
20*08314e7cSSumit Garg *
21*08314e7cSSumit Garg * PAS context is device-resource managed, so the caller does not need
22*08314e7cSSumit Garg * to worry about freeing the context memory.
23*08314e7cSSumit Garg *
24*08314e7cSSumit Garg * @dev: PAS firmware device
25*08314e7cSSumit Garg * @pas_id: peripheral authentication service id
26*08314e7cSSumit Garg * @mem_phys: Subsystem reserve memory start address
27*08314e7cSSumit Garg * @mem_size: Subsystem reserve memory size
28*08314e7cSSumit Garg *
29*08314e7cSSumit Garg * Return: The new PAS context, or ERR_PTR() on failure.
30*08314e7cSSumit Garg */
devm_qcom_pas_context_alloc(struct device * dev,u32 pas_id,phys_addr_t mem_phys,size_t mem_size)31*08314e7cSSumit Garg struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
32*08314e7cSSumit Garg u32 pas_id,
33*08314e7cSSumit Garg phys_addr_t mem_phys,
34*08314e7cSSumit Garg size_t mem_size)
35*08314e7cSSumit Garg {
36*08314e7cSSumit Garg struct qcom_pas_context *ctx;
37*08314e7cSSumit Garg
38*08314e7cSSumit Garg ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
39*08314e7cSSumit Garg if (!ctx)
40*08314e7cSSumit Garg return ERR_PTR(-ENOMEM);
41*08314e7cSSumit Garg
42*08314e7cSSumit Garg ctx->dev = dev;
43*08314e7cSSumit Garg ctx->pas_id = pas_id;
44*08314e7cSSumit Garg ctx->mem_phys = mem_phys;
45*08314e7cSSumit Garg ctx->mem_size = mem_size;
46*08314e7cSSumit Garg
47*08314e7cSSumit Garg return ctx;
48*08314e7cSSumit Garg }
49*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
50*08314e7cSSumit Garg
51*08314e7cSSumit Garg /**
52*08314e7cSSumit Garg * qcom_pas_init_image() - Initialize peripheral authentication service state
53*08314e7cSSumit Garg * machine for a given peripheral, using the metadata
54*08314e7cSSumit Garg * @pas_id: peripheral authentication service id
55*08314e7cSSumit Garg * @metadata: pointer to memory containing ELF header, program header table
56*08314e7cSSumit Garg * and optional blob of data used for authenticating the metadata
57*08314e7cSSumit Garg * and the rest of the firmware
58*08314e7cSSumit Garg * @size: size of the metadata
59*08314e7cSSumit Garg * @ctx: optional pas context
60*08314e7cSSumit Garg *
61*08314e7cSSumit Garg * Return: 0 on success.
62*08314e7cSSumit Garg *
63*08314e7cSSumit Garg * Upon successful return, the PAS metadata context (@ctx) will be used to
64*08314e7cSSumit Garg * track the metadata allocation, this needs to be released by invoking
65*08314e7cSSumit Garg * qcom_pas_metadata_release() by the caller.
66*08314e7cSSumit Garg */
qcom_pas_init_image(u32 pas_id,const void * metadata,size_t size,struct qcom_pas_context * ctx)67*08314e7cSSumit Garg int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
68*08314e7cSSumit Garg struct qcom_pas_context *ctx)
69*08314e7cSSumit Garg {
70*08314e7cSSumit Garg if (!ops_ptr)
71*08314e7cSSumit Garg return -ENODEV;
72*08314e7cSSumit Garg
73*08314e7cSSumit Garg return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
74*08314e7cSSumit Garg }
75*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_init_image);
76*08314e7cSSumit Garg
77*08314e7cSSumit Garg /**
78*08314e7cSSumit Garg * qcom_pas_metadata_release() - release metadata context
79*08314e7cSSumit Garg * @ctx: pas context
80*08314e7cSSumit Garg */
qcom_pas_metadata_release(struct qcom_pas_context * ctx)81*08314e7cSSumit Garg void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
82*08314e7cSSumit Garg {
83*08314e7cSSumit Garg if (!ops_ptr || !ctx || !ctx->ptr)
84*08314e7cSSumit Garg return;
85*08314e7cSSumit Garg
86*08314e7cSSumit Garg ops_ptr->metadata_release(ops_ptr->dev, ctx);
87*08314e7cSSumit Garg }
88*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
89*08314e7cSSumit Garg
90*08314e7cSSumit Garg /**
91*08314e7cSSumit Garg * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
92*08314e7cSSumit Garg * for firmware loading
93*08314e7cSSumit Garg * @pas_id: peripheral authentication service id
94*08314e7cSSumit Garg * @addr: start address of memory area to prepare
95*08314e7cSSumit Garg * @size: size of the memory area to prepare
96*08314e7cSSumit Garg *
97*08314e7cSSumit Garg * Return: 0 on success.
98*08314e7cSSumit Garg */
qcom_pas_mem_setup(u32 pas_id,phys_addr_t addr,phys_addr_t size)99*08314e7cSSumit Garg int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
100*08314e7cSSumit Garg {
101*08314e7cSSumit Garg if (!ops_ptr)
102*08314e7cSSumit Garg return -ENODEV;
103*08314e7cSSumit Garg
104*08314e7cSSumit Garg return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
105*08314e7cSSumit Garg }
106*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
107*08314e7cSSumit Garg
108*08314e7cSSumit Garg /**
109*08314e7cSSumit Garg * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
110*08314e7cSSumit Garg * for a given peripheral.
111*08314e7cSSumit Garg *
112*08314e7cSSumit Garg * Qualcomm remote processor may rely on both static and dynamic resources for
113*08314e7cSSumit Garg * its functionality. Static resources typically refer to memory-mapped
114*08314e7cSSumit Garg * addresses required by the subsystem and are often embedded within the
115*08314e7cSSumit Garg * firmware binary and dynamic resources, such as shared memory in DDR etc.,
116*08314e7cSSumit Garg * are determined at runtime during the boot process.
117*08314e7cSSumit Garg *
118*08314e7cSSumit Garg * On Qualcomm Technologies devices, it's possible that static resources are
119*08314e7cSSumit Garg * not embedded in the firmware binary and instead are provided by TrustZone.
120*08314e7cSSumit Garg * However, dynamic resources are always expected to come from TrustZone. This
121*08314e7cSSumit Garg * indicates that for Qualcomm devices, all resources (static and dynamic) will
122*08314e7cSSumit Garg * be provided by TrustZone PAS service.
123*08314e7cSSumit Garg *
124*08314e7cSSumit Garg * If the remote processor firmware binary does contain static resources, they
125*08314e7cSSumit Garg * should be passed in input_rt. These will be forwarded to TrustZone for
126*08314e7cSSumit Garg * authentication. TrustZone will then append the dynamic resources and return
127*08314e7cSSumit Garg * the complete resource table in output_rt_tzm.
128*08314e7cSSumit Garg *
129*08314e7cSSumit Garg * If the remote processor firmware binary does not include a resource table,
130*08314e7cSSumit Garg * the caller of this function should set input_rt as NULL and input_rt_size
131*08314e7cSSumit Garg * as zero respectively.
132*08314e7cSSumit Garg *
133*08314e7cSSumit Garg * More about documentation on resource table data structures can be found in
134*08314e7cSSumit Garg * include/linux/remoteproc.h
135*08314e7cSSumit Garg *
136*08314e7cSSumit Garg * @ctx: PAS context
137*08314e7cSSumit Garg * @input_rt: resource table buffer which is present in firmware binary
138*08314e7cSSumit Garg * @input_rt_size: size of the resource table present in firmware binary
139*08314e7cSSumit Garg * @output_rt_size: TrustZone expects caller should pass worst case size for
140*08314e7cSSumit Garg * the output_rt_tzm.
141*08314e7cSSumit Garg *
142*08314e7cSSumit Garg * Return:
143*08314e7cSSumit Garg * On success, returns a pointer to the allocated buffer containing the final
144*08314e7cSSumit Garg * resource table and output_rt_size will have actual resource table size from
145*08314e7cSSumit Garg * TrustZone. The caller is responsible for freeing the buffer. On failure,
146*08314e7cSSumit Garg * returns ERR_PTR(-errno).
147*08314e7cSSumit Garg */
qcom_pas_get_rsc_table(struct qcom_pas_context * ctx,void * input_rt,size_t input_rt_size,size_t * output_rt_size)148*08314e7cSSumit Garg struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
149*08314e7cSSumit Garg void *input_rt,
150*08314e7cSSumit Garg size_t input_rt_size,
151*08314e7cSSumit Garg size_t *output_rt_size)
152*08314e7cSSumit Garg {
153*08314e7cSSumit Garg if (!ops_ptr)
154*08314e7cSSumit Garg return ERR_PTR(-ENODEV);
155*08314e7cSSumit Garg if (!ctx)
156*08314e7cSSumit Garg return ERR_PTR(-EINVAL);
157*08314e7cSSumit Garg
158*08314e7cSSumit Garg return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
159*08314e7cSSumit Garg input_rt_size, output_rt_size);
160*08314e7cSSumit Garg }
161*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
162*08314e7cSSumit Garg
163*08314e7cSSumit Garg /**
164*08314e7cSSumit Garg * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
165*08314e7cSSumit Garg * and reset the remote processor
166*08314e7cSSumit Garg * @pas_id: peripheral authentication service id
167*08314e7cSSumit Garg *
168*08314e7cSSumit Garg * Return: 0 on success.
169*08314e7cSSumit Garg */
qcom_pas_auth_and_reset(u32 pas_id)170*08314e7cSSumit Garg int qcom_pas_auth_and_reset(u32 pas_id)
171*08314e7cSSumit Garg {
172*08314e7cSSumit Garg if (!ops_ptr)
173*08314e7cSSumit Garg return -ENODEV;
174*08314e7cSSumit Garg
175*08314e7cSSumit Garg return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
176*08314e7cSSumit Garg }
177*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
178*08314e7cSSumit Garg
179*08314e7cSSumit Garg /**
180*08314e7cSSumit Garg * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
181*08314e7cSSumit Garg * remote processor
182*08314e7cSSumit Garg *
183*08314e7cSSumit Garg * @ctx: Context saved during call to devm_qcom_pas_context_alloc()
184*08314e7cSSumit Garg *
185*08314e7cSSumit Garg * This function performs the necessary steps to prepare a PAS subsystem,
186*08314e7cSSumit Garg * authenticate it using the provided metadata, and initiate a reset sequence.
187*08314e7cSSumit Garg *
188*08314e7cSSumit Garg * It should be used when Linux is in control setting up the IOMMU hardware
189*08314e7cSSumit Garg * for remote subsystem during secure firmware loading processes. The
190*08314e7cSSumit Garg * preparation step sets up a shmbridge over the firmware memory before
191*08314e7cSSumit Garg * TrustZone accesses the firmware memory region for authentication. The
192*08314e7cSSumit Garg * authentication step verifies the integrity and authenticity of the firmware
193*08314e7cSSumit Garg * or configuration using secure metadata. Finally, the reset step ensures the
194*08314e7cSSumit Garg * subsystem starts in a clean and sane state.
195*08314e7cSSumit Garg *
196*08314e7cSSumit Garg * Return: 0 on success, negative errno on failure.
197*08314e7cSSumit Garg */
qcom_pas_prepare_and_auth_reset(struct qcom_pas_context * ctx)198*08314e7cSSumit Garg int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
199*08314e7cSSumit Garg {
200*08314e7cSSumit Garg if (!ops_ptr)
201*08314e7cSSumit Garg return -ENODEV;
202*08314e7cSSumit Garg if (!ctx)
203*08314e7cSSumit Garg return -EINVAL;
204*08314e7cSSumit Garg
205*08314e7cSSumit Garg return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
206*08314e7cSSumit Garg }
207*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
208*08314e7cSSumit Garg
209*08314e7cSSumit Garg /**
210*08314e7cSSumit Garg * qcom_pas_set_remote_state() - Set the remote processor state
211*08314e7cSSumit Garg * @state: peripheral state
212*08314e7cSSumit Garg * @pas_id: peripheral authentication service id
213*08314e7cSSumit Garg *
214*08314e7cSSumit Garg * Return: 0 on success.
215*08314e7cSSumit Garg */
qcom_pas_set_remote_state(u32 state,u32 pas_id)216*08314e7cSSumit Garg int qcom_pas_set_remote_state(u32 state, u32 pas_id)
217*08314e7cSSumit Garg {
218*08314e7cSSumit Garg if (!ops_ptr)
219*08314e7cSSumit Garg return -ENODEV;
220*08314e7cSSumit Garg
221*08314e7cSSumit Garg return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
222*08314e7cSSumit Garg }
223*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
224*08314e7cSSumit Garg
225*08314e7cSSumit Garg /**
226*08314e7cSSumit Garg * qcom_pas_shutdown() - Shut down the remote processor
227*08314e7cSSumit Garg * @pas_id: peripheral authentication service id
228*08314e7cSSumit Garg *
229*08314e7cSSumit Garg * Return: 0 on success.
230*08314e7cSSumit Garg */
qcom_pas_shutdown(u32 pas_id)231*08314e7cSSumit Garg int qcom_pas_shutdown(u32 pas_id)
232*08314e7cSSumit Garg {
233*08314e7cSSumit Garg if (!ops_ptr)
234*08314e7cSSumit Garg return -ENODEV;
235*08314e7cSSumit Garg
236*08314e7cSSumit Garg return ops_ptr->shutdown(ops_ptr->dev, pas_id);
237*08314e7cSSumit Garg }
238*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
239*08314e7cSSumit Garg
240*08314e7cSSumit Garg /**
241*08314e7cSSumit Garg * qcom_pas_supported() - Check if the peripheral authentication service is
242*08314e7cSSumit Garg * supported for the given peripheral
243*08314e7cSSumit Garg * @pas_id: peripheral authentication service id
244*08314e7cSSumit Garg *
245*08314e7cSSumit Garg * Return: true if PAS is supported for this peripheral, otherwise false.
246*08314e7cSSumit Garg */
qcom_pas_supported(u32 pas_id)247*08314e7cSSumit Garg bool qcom_pas_supported(u32 pas_id)
248*08314e7cSSumit Garg {
249*08314e7cSSumit Garg if (!ops_ptr)
250*08314e7cSSumit Garg return false;
251*08314e7cSSumit Garg
252*08314e7cSSumit Garg return ops_ptr->supported(ops_ptr->dev, pas_id);
253*08314e7cSSumit Garg }
254*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_supported);
255*08314e7cSSumit Garg
256*08314e7cSSumit Garg /**
257*08314e7cSSumit Garg * qcom_pas_is_available() - Check if the peripheral authentication service is
258*08314e7cSSumit Garg * available. Note that it is mandatory for any PAS
259*08314e7cSSumit Garg * client to invoke this API. If it returns true then
260*08314e7cSSumit Garg * only any other PAS API can be invoked.
261*08314e7cSSumit Garg *
262*08314e7cSSumit Garg * Return: true if PAS is available, otherwise false.
263*08314e7cSSumit Garg */
qcom_pas_is_available(void)264*08314e7cSSumit Garg bool qcom_pas_is_available(void)
265*08314e7cSSumit Garg {
266*08314e7cSSumit Garg /*
267*08314e7cSSumit Garg * The barrier for ops_ptr is intended to synchronize the data stores
268*08314e7cSSumit Garg * for the ops data structure when client drivers are in parallel
269*08314e7cSSumit Garg * checking for PAS service availability.
270*08314e7cSSumit Garg *
271*08314e7cSSumit Garg * Once the PAS backend becomes available, it is allowed for multiple
272*08314e7cSSumit Garg * threads to enter TZ for parallel bringup of co-processors during
273*08314e7cSSumit Garg * boot.
274*08314e7cSSumit Garg */
275*08314e7cSSumit Garg return !!smp_load_acquire(&ops_ptr);
276*08314e7cSSumit Garg }
277*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_is_available);
278*08314e7cSSumit Garg
qcom_pas_ops_register(struct qcom_pas_ops * ops)279*08314e7cSSumit Garg void qcom_pas_ops_register(struct qcom_pas_ops *ops)
280*08314e7cSSumit Garg {
281*08314e7cSSumit Garg if (!qcom_pas_is_available())
282*08314e7cSSumit Garg /* Paired with smp_load_acquire() in qcom_pas_is_available() */
283*08314e7cSSumit Garg smp_store_release(&ops_ptr, ops);
284*08314e7cSSumit Garg else
285*08314e7cSSumit Garg pr_err("qcom_pas: ops already registered by %s\n",
286*08314e7cSSumit Garg ops_ptr->drv_name);
287*08314e7cSSumit Garg }
288*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
289*08314e7cSSumit Garg
qcom_pas_ops_unregister(void)290*08314e7cSSumit Garg void qcom_pas_ops_unregister(void)
291*08314e7cSSumit Garg {
292*08314e7cSSumit Garg /* Paired with smp_load_acquire() in qcom_pas_is_available() */
293*08314e7cSSumit Garg smp_store_release(&ops_ptr, NULL);
294*08314e7cSSumit Garg }
295*08314e7cSSumit Garg EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
296*08314e7cSSumit Garg
297*08314e7cSSumit Garg MODULE_LICENSE("GPL");
298*08314e7cSSumit Garg MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver");
299