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