xref: /linux/drivers/firmware/qcom/qcom_pas.c (revision edc84a9396acf1a0e78c46230dd0bcee1b84ac53)
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