mic: vop: Fix use-after-free on remove
[linux/fpc-iii.git] / drivers / firmware / xilinx / zynqmp.c
blob9a1c72a9280f1bce66ee5544e39b8b8abf86638c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Xilinx Zynq MPSoC Firmware layer
5 * Copyright (C) 2014-2018 Xilinx, Inc.
7 * Michal Simek <michal.simek@xilinx.com>
8 * Davorin Mista <davorin.mista@aggios.com>
9 * Jolly Shah <jollys@xilinx.com>
10 * Rajan Vaja <rajanv@xilinx.com>
13 #include <linux/arm-smccc.h>
14 #include <linux/compiler.h>
15 #include <linux/device.h>
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/of_platform.h>
20 #include <linux/slab.h>
21 #include <linux/uaccess.h>
23 #include <linux/firmware/xlnx-zynqmp.h>
24 #include "zynqmp-debug.h"
26 /**
27 * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
28 * @ret_status: PMUFW return code
30 * Return: corresponding Linux error code
32 static int zynqmp_pm_ret_code(u32 ret_status)
34 switch (ret_status) {
35 case XST_PM_SUCCESS:
36 case XST_PM_DOUBLE_REQ:
37 return 0;
38 case XST_PM_NO_ACCESS:
39 return -EACCES;
40 case XST_PM_ABORT_SUSPEND:
41 return -ECANCELED;
42 case XST_PM_INTERNAL:
43 case XST_PM_CONFLICT:
44 case XST_PM_INVALID_NODE:
45 default:
46 return -EINVAL;
50 static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
51 u32 *ret_payload)
53 return -ENODEV;
57 * PM function call wrapper
58 * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
60 static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
62 /**
63 * do_fw_call_smc() - Call system-level platform management layer (SMC)
64 * @arg0: Argument 0 to SMC call
65 * @arg1: Argument 1 to SMC call
66 * @arg2: Argument 2 to SMC call
67 * @ret_payload: Returned value array
69 * Invoke platform management function via SMC call (no hypervisor present).
71 * Return: Returns status, either success or error+reason
73 static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
74 u32 *ret_payload)
76 struct arm_smccc_res res;
78 arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
80 if (ret_payload) {
81 ret_payload[0] = lower_32_bits(res.a0);
82 ret_payload[1] = upper_32_bits(res.a0);
83 ret_payload[2] = lower_32_bits(res.a1);
84 ret_payload[3] = upper_32_bits(res.a1);
87 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
90 /**
91 * do_fw_call_hvc() - Call system-level platform management layer (HVC)
92 * @arg0: Argument 0 to HVC call
93 * @arg1: Argument 1 to HVC call
94 * @arg2: Argument 2 to HVC call
95 * @ret_payload: Returned value array
97 * Invoke platform management function via HVC
98 * HVC-based for communication through hypervisor
99 * (no direct communication with ATF).
101 * Return: Returns status, either success or error+reason
103 static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
104 u32 *ret_payload)
106 struct arm_smccc_res res;
108 arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
110 if (ret_payload) {
111 ret_payload[0] = lower_32_bits(res.a0);
112 ret_payload[1] = upper_32_bits(res.a0);
113 ret_payload[2] = lower_32_bits(res.a1);
114 ret_payload[3] = upper_32_bits(res.a1);
117 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
121 * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
122 * caller function depending on the configuration
123 * @pm_api_id: Requested PM-API call
124 * @arg0: Argument 0 to requested PM-API call
125 * @arg1: Argument 1 to requested PM-API call
126 * @arg2: Argument 2 to requested PM-API call
127 * @arg3: Argument 3 to requested PM-API call
128 * @ret_payload: Returned value array
130 * Invoke platform management function for SMC or HVC call, depending on
131 * configuration.
132 * Following SMC Calling Convention (SMCCC) for SMC64:
133 * Pm Function Identifier,
134 * PM_SIP_SVC + PM_API_ID =
135 * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
136 * ((SMC_64) << FUNCID_CC_SHIFT)
137 * ((SIP_START) << FUNCID_OEN_SHIFT)
138 * ((PM_API_ID) & FUNCID_NUM_MASK))
140 * PM_SIP_SVC - Registered ZynqMP SIP Service Call.
141 * PM_API_ID - Platform Management API ID.
143 * Return: Returns status, either success or error+reason
145 int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
146 u32 arg2, u32 arg3, u32 *ret_payload)
149 * Added SIP service call Function Identifier
150 * Make sure to stay in x0 register
152 u64 smc_arg[4];
154 smc_arg[0] = PM_SIP_SVC | pm_api_id;
155 smc_arg[1] = ((u64)arg1 << 32) | arg0;
156 smc_arg[2] = ((u64)arg3 << 32) | arg2;
158 return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
161 static u32 pm_api_version;
162 static u32 pm_tz_version;
165 * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
166 * @version: Returned version value
168 * Return: Returns status, either success or error+reason
170 static int zynqmp_pm_get_api_version(u32 *version)
172 u32 ret_payload[PAYLOAD_ARG_CNT];
173 int ret;
175 if (!version)
176 return -EINVAL;
178 /* Check is PM API version already verified */
179 if (pm_api_version > 0) {
180 *version = pm_api_version;
181 return 0;
183 ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload);
184 *version = ret_payload[1];
186 return ret;
190 * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
191 * @version: Returned version value
193 * Return: Returns status, either success or error+reason
195 static int zynqmp_pm_get_trustzone_version(u32 *version)
197 u32 ret_payload[PAYLOAD_ARG_CNT];
198 int ret;
200 if (!version)
201 return -EINVAL;
203 /* Check is PM trustzone version already verified */
204 if (pm_tz_version > 0) {
205 *version = pm_tz_version;
206 return 0;
208 ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0,
209 0, 0, ret_payload);
210 *version = ret_payload[1];
212 return ret;
216 * get_set_conduit_method() - Choose SMC or HVC based communication
217 * @np: Pointer to the device_node structure
219 * Use SMC or HVC-based functions to communicate with EL2/EL3.
221 * Return: Returns 0 on success or error code
223 static int get_set_conduit_method(struct device_node *np)
225 const char *method;
227 if (of_property_read_string(np, "method", &method)) {
228 pr_warn("%s missing \"method\" property\n", __func__);
229 return -ENXIO;
232 if (!strcmp("hvc", method)) {
233 do_fw_call = do_fw_call_hvc;
234 } else if (!strcmp("smc", method)) {
235 do_fw_call = do_fw_call_smc;
236 } else {
237 pr_warn("%s Invalid \"method\" property: %s\n",
238 __func__, method);
239 return -EINVAL;
242 return 0;
246 * zynqmp_pm_query_data() - Get query data from firmware
247 * @qdata: Variable to the zynqmp_pm_query_data structure
248 * @out: Returned output value
250 * Return: Returns status, either success or error+reason
252 static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
254 int ret;
256 ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
257 qdata.arg2, qdata.arg3, out);
260 * For clock name query, all bytes in SMC response are clock name
261 * characters and return code is always success. For invalid clocks,
262 * clock name bytes would be zeros.
264 return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
268 * zynqmp_pm_clock_enable() - Enable the clock for given id
269 * @clock_id: ID of the clock to be enabled
271 * This function is used by master to enable the clock
272 * including peripherals and PLL clocks.
274 * Return: Returns status, either success or error+reason
276 static int zynqmp_pm_clock_enable(u32 clock_id)
278 return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
282 * zynqmp_pm_clock_disable() - Disable the clock for given id
283 * @clock_id: ID of the clock to be disable
285 * This function is used by master to disable the clock
286 * including peripherals and PLL clocks.
288 * Return: Returns status, either success or error+reason
290 static int zynqmp_pm_clock_disable(u32 clock_id)
292 return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
296 * zynqmp_pm_clock_getstate() - Get the clock state for given id
297 * @clock_id: ID of the clock to be queried
298 * @state: 1/0 (Enabled/Disabled)
300 * This function is used by master to get the state of clock
301 * including peripherals and PLL clocks.
303 * Return: Returns status, either success or error+reason
305 static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
307 u32 ret_payload[PAYLOAD_ARG_CNT];
308 int ret;
310 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
311 0, 0, ret_payload);
312 *state = ret_payload[1];
314 return ret;
318 * zynqmp_pm_clock_setdivider() - Set the clock divider for given id
319 * @clock_id: ID of the clock
320 * @divider: divider value
322 * This function is used by master to set divider for any clock
323 * to achieve desired rate.
325 * Return: Returns status, either success or error+reason
327 static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
329 return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
330 0, 0, NULL);
334 * zynqmp_pm_clock_getdivider() - Get the clock divider for given id
335 * @clock_id: ID of the clock
336 * @divider: divider value
338 * This function is used by master to get divider values
339 * for any clock.
341 * Return: Returns status, either success or error+reason
343 static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
345 u32 ret_payload[PAYLOAD_ARG_CNT];
346 int ret;
348 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
349 0, 0, ret_payload);
350 *divider = ret_payload[1];
352 return ret;
356 * zynqmp_pm_clock_setrate() - Set the clock rate for given id
357 * @clock_id: ID of the clock
358 * @rate: rate value in hz
360 * This function is used by master to set rate for any clock.
362 * Return: Returns status, either success or error+reason
364 static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
366 return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
367 lower_32_bits(rate),
368 upper_32_bits(rate),
369 0, NULL);
373 * zynqmp_pm_clock_getrate() - Get the clock rate for given id
374 * @clock_id: ID of the clock
375 * @rate: rate value in hz
377 * This function is used by master to get rate
378 * for any clock.
380 * Return: Returns status, either success or error+reason
382 static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
384 u32 ret_payload[PAYLOAD_ARG_CNT];
385 int ret;
387 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
388 0, 0, ret_payload);
389 *rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
391 return ret;
395 * zynqmp_pm_clock_setparent() - Set the clock parent for given id
396 * @clock_id: ID of the clock
397 * @parent_id: parent id
399 * This function is used by master to set parent for any clock.
401 * Return: Returns status, either success or error+reason
403 static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
405 return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
406 parent_id, 0, 0, NULL);
410 * zynqmp_pm_clock_getparent() - Get the clock parent for given id
411 * @clock_id: ID of the clock
412 * @parent_id: parent id
414 * This function is used by master to get parent index
415 * for any clock.
417 * Return: Returns status, either success or error+reason
419 static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
421 u32 ret_payload[PAYLOAD_ARG_CNT];
422 int ret;
424 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
425 0, 0, ret_payload);
426 *parent_id = ret_payload[1];
428 return ret;
432 * zynqmp_is_valid_ioctl() - Check whether IOCTL ID is valid or not
433 * @ioctl_id: IOCTL ID
435 * Return: 1 if IOCTL is valid else 0
437 static inline int zynqmp_is_valid_ioctl(u32 ioctl_id)
439 switch (ioctl_id) {
440 case IOCTL_SET_PLL_FRAC_MODE:
441 case IOCTL_GET_PLL_FRAC_MODE:
442 case IOCTL_SET_PLL_FRAC_DATA:
443 case IOCTL_GET_PLL_FRAC_DATA:
444 return 1;
445 default:
446 return 0;
451 * zynqmp_pm_ioctl() - PM IOCTL API for device control and configs
452 * @node_id: Node ID of the device
453 * @ioctl_id: ID of the requested IOCTL
454 * @arg1: Argument 1 to requested IOCTL call
455 * @arg2: Argument 2 to requested IOCTL call
456 * @out: Returned output value
458 * This function calls IOCTL to firmware for device control and configuration.
460 * Return: Returns status, either success or error+reason
462 static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
463 u32 *out)
465 if (!zynqmp_is_valid_ioctl(ioctl_id))
466 return -EINVAL;
468 return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, ioctl_id,
469 arg1, arg2, out);
472 static const struct zynqmp_eemi_ops eemi_ops = {
473 .get_api_version = zynqmp_pm_get_api_version,
474 .query_data = zynqmp_pm_query_data,
475 .clock_enable = zynqmp_pm_clock_enable,
476 .clock_disable = zynqmp_pm_clock_disable,
477 .clock_getstate = zynqmp_pm_clock_getstate,
478 .clock_setdivider = zynqmp_pm_clock_setdivider,
479 .clock_getdivider = zynqmp_pm_clock_getdivider,
480 .clock_setrate = zynqmp_pm_clock_setrate,
481 .clock_getrate = zynqmp_pm_clock_getrate,
482 .clock_setparent = zynqmp_pm_clock_setparent,
483 .clock_getparent = zynqmp_pm_clock_getparent,
484 .ioctl = zynqmp_pm_ioctl,
488 * zynqmp_pm_get_eemi_ops - Get eemi ops functions
490 * Return: Pointer of eemi_ops structure
492 const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
494 return &eemi_ops;
496 EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
498 static int zynqmp_firmware_probe(struct platform_device *pdev)
500 struct device *dev = &pdev->dev;
501 struct device_node *np;
502 int ret;
504 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
505 if (!np)
506 return 0;
507 of_node_put(np);
509 ret = get_set_conduit_method(dev->of_node);
510 if (ret)
511 return ret;
513 /* Check PM API version number */
514 zynqmp_pm_get_api_version(&pm_api_version);
515 if (pm_api_version < ZYNQMP_PM_VERSION) {
516 panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",
517 __func__,
518 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR,
519 pm_api_version >> 16, pm_api_version & 0xFFFF);
522 pr_info("%s Platform Management API v%d.%d\n", __func__,
523 pm_api_version >> 16, pm_api_version & 0xFFFF);
525 /* Check trustzone version number */
526 ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);
527 if (ret)
528 panic("Legacy trustzone found without version support\n");
530 if (pm_tz_version < ZYNQMP_TZ_VERSION)
531 panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",
532 __func__,
533 ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR,
534 pm_tz_version >> 16, pm_tz_version & 0xFFFF);
536 pr_info("%s Trustzone version v%d.%d\n", __func__,
537 pm_tz_version >> 16, pm_tz_version & 0xFFFF);
539 zynqmp_pm_api_debugfs_init();
541 return of_platform_populate(dev->of_node, NULL, NULL, dev);
544 static int zynqmp_firmware_remove(struct platform_device *pdev)
546 zynqmp_pm_api_debugfs_exit();
548 return 0;
551 static const struct of_device_id zynqmp_firmware_of_match[] = {
552 {.compatible = "xlnx,zynqmp-firmware"},
555 MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);
557 static struct platform_driver zynqmp_firmware_driver = {
558 .driver = {
559 .name = "zynqmp_firmware",
560 .of_match_table = zynqmp_firmware_of_match,
562 .probe = zynqmp_firmware_probe,
563 .remove = zynqmp_firmware_remove,
565 module_platform_driver(zynqmp_firmware_driver);