1 // SPDX-License-Identifier: GPL-2.0
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/mfd/core.h>
18 #include <linux/module.h>
20 #include <linux/of_platform.h>
21 #include <linux/slab.h>
22 #include <linux/uaccess.h>
24 #include <linux/firmware/xlnx-zynqmp.h>
25 #include "zynqmp-debug.h"
27 static const struct zynqmp_eemi_ops
*eemi_ops_tbl
;
29 static bool feature_check_enabled
;
30 static u32 zynqmp_pm_features
[PM_API_MAX
];
32 static const struct mfd_cell firmware_devs
[] = {
34 .name
= "zynqmp_power_controller",
39 * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
40 * @ret_status: PMUFW return code
42 * Return: corresponding Linux error code
44 static int zynqmp_pm_ret_code(u32 ret_status
)
48 case XST_PM_DOUBLE_REQ
:
50 case XST_PM_NO_FEATURE
:
52 case XST_PM_NO_ACCESS
:
54 case XST_PM_ABORT_SUSPEND
:
56 case XST_PM_MULT_USER
:
60 case XST_PM_INVALID_NODE
:
66 static noinline
int do_fw_call_fail(u64 arg0
, u64 arg1
, u64 arg2
,
73 * PM function call wrapper
74 * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
76 static int (*do_fw_call
)(u64
, u64
, u64
, u32
*ret_payload
) = do_fw_call_fail
;
79 * do_fw_call_smc() - Call system-level platform management layer (SMC)
80 * @arg0: Argument 0 to SMC call
81 * @arg1: Argument 1 to SMC call
82 * @arg2: Argument 2 to SMC call
83 * @ret_payload: Returned value array
85 * Invoke platform management function via SMC call (no hypervisor present).
87 * Return: Returns status, either success or error+reason
89 static noinline
int do_fw_call_smc(u64 arg0
, u64 arg1
, u64 arg2
,
92 struct arm_smccc_res res
;
94 arm_smccc_smc(arg0
, arg1
, arg2
, 0, 0, 0, 0, 0, &res
);
97 ret_payload
[0] = lower_32_bits(res
.a0
);
98 ret_payload
[1] = upper_32_bits(res
.a0
);
99 ret_payload
[2] = lower_32_bits(res
.a1
);
100 ret_payload
[3] = upper_32_bits(res
.a1
);
103 return zynqmp_pm_ret_code((enum pm_ret_status
)res
.a0
);
107 * do_fw_call_hvc() - Call system-level platform management layer (HVC)
108 * @arg0: Argument 0 to HVC call
109 * @arg1: Argument 1 to HVC call
110 * @arg2: Argument 2 to HVC call
111 * @ret_payload: Returned value array
113 * Invoke platform management function via HVC
114 * HVC-based for communication through hypervisor
115 * (no direct communication with ATF).
117 * Return: Returns status, either success or error+reason
119 static noinline
int do_fw_call_hvc(u64 arg0
, u64 arg1
, u64 arg2
,
122 struct arm_smccc_res res
;
124 arm_smccc_hvc(arg0
, arg1
, arg2
, 0, 0, 0, 0, 0, &res
);
127 ret_payload
[0] = lower_32_bits(res
.a0
);
128 ret_payload
[1] = upper_32_bits(res
.a0
);
129 ret_payload
[2] = lower_32_bits(res
.a1
);
130 ret_payload
[3] = upper_32_bits(res
.a1
);
133 return zynqmp_pm_ret_code((enum pm_ret_status
)res
.a0
);
137 * zynqmp_pm_feature() - Check weather given feature is supported or not
138 * @api_id: API ID to check
140 * Return: Returns status, either success or error+reason
142 static int zynqmp_pm_feature(u32 api_id
)
145 u32 ret_payload
[PAYLOAD_ARG_CNT
];
148 if (!feature_check_enabled
)
151 /* Return value if feature is already checked */
152 if (zynqmp_pm_features
[api_id
] != PM_FEATURE_UNCHECKED
)
153 return zynqmp_pm_features
[api_id
];
155 smc_arg
[0] = PM_SIP_SVC
| PM_FEATURE_CHECK
;
158 ret
= do_fw_call(smc_arg
[0], smc_arg
[1], 0, ret_payload
);
160 zynqmp_pm_features
[api_id
] = PM_FEATURE_INVALID
;
161 return PM_FEATURE_INVALID
;
164 zynqmp_pm_features
[api_id
] = ret_payload
[1];
166 return zynqmp_pm_features
[api_id
];
170 * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
171 * caller function depending on the configuration
172 * @pm_api_id: Requested PM-API call
173 * @arg0: Argument 0 to requested PM-API call
174 * @arg1: Argument 1 to requested PM-API call
175 * @arg2: Argument 2 to requested PM-API call
176 * @arg3: Argument 3 to requested PM-API call
177 * @ret_payload: Returned value array
179 * Invoke platform management function for SMC or HVC call, depending on
181 * Following SMC Calling Convention (SMCCC) for SMC64:
182 * Pm Function Identifier,
183 * PM_SIP_SVC + PM_API_ID =
184 * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
185 * ((SMC_64) << FUNCID_CC_SHIFT)
186 * ((SIP_START) << FUNCID_OEN_SHIFT)
187 * ((PM_API_ID) & FUNCID_NUM_MASK))
189 * PM_SIP_SVC - Registered ZynqMP SIP Service Call.
190 * PM_API_ID - Platform Management API ID.
192 * Return: Returns status, either success or error+reason
194 int zynqmp_pm_invoke_fn(u32 pm_api_id
, u32 arg0
, u32 arg1
,
195 u32 arg2
, u32 arg3
, u32
*ret_payload
)
198 * Added SIP service call Function Identifier
199 * Make sure to stay in x0 register
203 if (zynqmp_pm_feature(pm_api_id
) == PM_FEATURE_INVALID
)
206 smc_arg
[0] = PM_SIP_SVC
| pm_api_id
;
207 smc_arg
[1] = ((u64
)arg1
<< 32) | arg0
;
208 smc_arg
[2] = ((u64
)arg3
<< 32) | arg2
;
210 return do_fw_call(smc_arg
[0], smc_arg
[1], smc_arg
[2], ret_payload
);
213 static u32 pm_api_version
;
214 static u32 pm_tz_version
;
217 * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
218 * @version: Returned version value
220 * Return: Returns status, either success or error+reason
222 static int zynqmp_pm_get_api_version(u32
*version
)
224 u32 ret_payload
[PAYLOAD_ARG_CNT
];
230 /* Check is PM API version already verified */
231 if (pm_api_version
> 0) {
232 *version
= pm_api_version
;
235 ret
= zynqmp_pm_invoke_fn(PM_GET_API_VERSION
, 0, 0, 0, 0, ret_payload
);
236 *version
= ret_payload
[1];
242 * zynqmp_pm_get_chipid - Get silicon ID registers
243 * @idcode: IDCODE register
244 * @version: version register
246 * Return: Returns the status of the operation and the idcode and version
247 * registers in @idcode and @version.
249 static int zynqmp_pm_get_chipid(u32
*idcode
, u32
*version
)
251 u32 ret_payload
[PAYLOAD_ARG_CNT
];
254 if (!idcode
|| !version
)
257 ret
= zynqmp_pm_invoke_fn(PM_GET_CHIPID
, 0, 0, 0, 0, ret_payload
);
258 *idcode
= ret_payload
[1];
259 *version
= ret_payload
[2];
265 * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
266 * @version: Returned version value
268 * Return: Returns status, either success or error+reason
270 static int zynqmp_pm_get_trustzone_version(u32
*version
)
272 u32 ret_payload
[PAYLOAD_ARG_CNT
];
278 /* Check is PM trustzone version already verified */
279 if (pm_tz_version
> 0) {
280 *version
= pm_tz_version
;
283 ret
= zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION
, 0, 0,
285 *version
= ret_payload
[1];
291 * get_set_conduit_method() - Choose SMC or HVC based communication
292 * @np: Pointer to the device_node structure
294 * Use SMC or HVC-based functions to communicate with EL2/EL3.
296 * Return: Returns 0 on success or error code
298 static int get_set_conduit_method(struct device_node
*np
)
302 if (of_property_read_string(np
, "method", &method
)) {
303 pr_warn("%s missing \"method\" property\n", __func__
);
307 if (!strcmp("hvc", method
)) {
308 do_fw_call
= do_fw_call_hvc
;
309 } else if (!strcmp("smc", method
)) {
310 do_fw_call
= do_fw_call_smc
;
312 pr_warn("%s Invalid \"method\" property: %s\n",
321 * zynqmp_pm_query_data() - Get query data from firmware
322 * @qdata: Variable to the zynqmp_pm_query_data structure
323 * @out: Returned output value
325 * Return: Returns status, either success or error+reason
327 static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata
, u32
*out
)
331 ret
= zynqmp_pm_invoke_fn(PM_QUERY_DATA
, qdata
.qid
, qdata
.arg1
,
332 qdata
.arg2
, qdata
.arg3
, out
);
335 * For clock name query, all bytes in SMC response are clock name
336 * characters and return code is always success. For invalid clocks,
337 * clock name bytes would be zeros.
339 return qdata
.qid
== PM_QID_CLOCK_GET_NAME
? 0 : ret
;
343 * zynqmp_pm_clock_enable() - Enable the clock for given id
344 * @clock_id: ID of the clock to be enabled
346 * This function is used by master to enable the clock
347 * including peripherals and PLL clocks.
349 * Return: Returns status, either success or error+reason
351 static int zynqmp_pm_clock_enable(u32 clock_id
)
353 return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE
, clock_id
, 0, 0, 0, NULL
);
357 * zynqmp_pm_clock_disable() - Disable the clock for given id
358 * @clock_id: ID of the clock to be disable
360 * This function is used by master to disable the clock
361 * including peripherals and PLL clocks.
363 * Return: Returns status, either success or error+reason
365 static int zynqmp_pm_clock_disable(u32 clock_id
)
367 return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE
, clock_id
, 0, 0, 0, NULL
);
371 * zynqmp_pm_clock_getstate() - Get the clock state for given id
372 * @clock_id: ID of the clock to be queried
373 * @state: 1/0 (Enabled/Disabled)
375 * This function is used by master to get the state of clock
376 * including peripherals and PLL clocks.
378 * Return: Returns status, either success or error+reason
380 static int zynqmp_pm_clock_getstate(u32 clock_id
, u32
*state
)
382 u32 ret_payload
[PAYLOAD_ARG_CNT
];
385 ret
= zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE
, clock_id
, 0,
387 *state
= ret_payload
[1];
393 * zynqmp_pm_clock_setdivider() - Set the clock divider for given id
394 * @clock_id: ID of the clock
395 * @divider: divider value
397 * This function is used by master to set divider for any clock
398 * to achieve desired rate.
400 * Return: Returns status, either success or error+reason
402 static int zynqmp_pm_clock_setdivider(u32 clock_id
, u32 divider
)
404 return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER
, clock_id
, divider
,
409 * zynqmp_pm_clock_getdivider() - Get the clock divider for given id
410 * @clock_id: ID of the clock
411 * @divider: divider value
413 * This function is used by master to get divider values
416 * Return: Returns status, either success or error+reason
418 static int zynqmp_pm_clock_getdivider(u32 clock_id
, u32
*divider
)
420 u32 ret_payload
[PAYLOAD_ARG_CNT
];
423 ret
= zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER
, clock_id
, 0,
425 *divider
= ret_payload
[1];
431 * zynqmp_pm_clock_setrate() - Set the clock rate for given id
432 * @clock_id: ID of the clock
433 * @rate: rate value in hz
435 * This function is used by master to set rate for any clock.
437 * Return: Returns status, either success or error+reason
439 static int zynqmp_pm_clock_setrate(u32 clock_id
, u64 rate
)
441 return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE
, clock_id
,
448 * zynqmp_pm_clock_getrate() - Get the clock rate for given id
449 * @clock_id: ID of the clock
450 * @rate: rate value in hz
452 * This function is used by master to get rate
455 * Return: Returns status, either success or error+reason
457 static int zynqmp_pm_clock_getrate(u32 clock_id
, u64
*rate
)
459 u32 ret_payload
[PAYLOAD_ARG_CNT
];
462 ret
= zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE
, clock_id
, 0,
464 *rate
= ((u64
)ret_payload
[2] << 32) | ret_payload
[1];
470 * zynqmp_pm_clock_setparent() - Set the clock parent for given id
471 * @clock_id: ID of the clock
472 * @parent_id: parent id
474 * This function is used by master to set parent for any clock.
476 * Return: Returns status, either success or error+reason
478 static int zynqmp_pm_clock_setparent(u32 clock_id
, u32 parent_id
)
480 return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT
, clock_id
,
481 parent_id
, 0, 0, NULL
);
485 * zynqmp_pm_clock_getparent() - Get the clock parent for given id
486 * @clock_id: ID of the clock
487 * @parent_id: parent id
489 * This function is used by master to get parent index
492 * Return: Returns status, either success or error+reason
494 static int zynqmp_pm_clock_getparent(u32 clock_id
, u32
*parent_id
)
496 u32 ret_payload
[PAYLOAD_ARG_CNT
];
499 ret
= zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT
, clock_id
, 0,
501 *parent_id
= ret_payload
[1];
507 * zynqmp_is_valid_ioctl() - Check whether IOCTL ID is valid or not
508 * @ioctl_id: IOCTL ID
510 * Return: 1 if IOCTL is valid else 0
512 static inline int zynqmp_is_valid_ioctl(u32 ioctl_id
)
515 case IOCTL_SD_DLL_RESET
:
516 case IOCTL_SET_SD_TAPDELAY
:
517 case IOCTL_SET_PLL_FRAC_MODE
:
518 case IOCTL_GET_PLL_FRAC_MODE
:
519 case IOCTL_SET_PLL_FRAC_DATA
:
520 case IOCTL_GET_PLL_FRAC_DATA
:
528 * zynqmp_pm_ioctl() - PM IOCTL API for device control and configs
529 * @node_id: Node ID of the device
530 * @ioctl_id: ID of the requested IOCTL
531 * @arg1: Argument 1 to requested IOCTL call
532 * @arg2: Argument 2 to requested IOCTL call
533 * @out: Returned output value
535 * This function calls IOCTL to firmware for device control and configuration.
537 * Return: Returns status, either success or error+reason
539 static int zynqmp_pm_ioctl(u32 node_id
, u32 ioctl_id
, u32 arg1
, u32 arg2
,
542 if (!zynqmp_is_valid_ioctl(ioctl_id
))
545 return zynqmp_pm_invoke_fn(PM_IOCTL
, node_id
, ioctl_id
,
550 * zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release)
551 * @reset: Reset to be configured
552 * @assert_flag: Flag stating should reset be asserted (1) or
555 * Return: Returns status, either success or error+reason
557 static int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset
,
558 const enum zynqmp_pm_reset_action assert_flag
)
560 return zynqmp_pm_invoke_fn(PM_RESET_ASSERT
, reset
, assert_flag
,
565 * zynqmp_pm_reset_get_status - Get status of the reset
566 * @reset: Reset whose status should be returned
567 * @status: Returned status
569 * Return: Returns status, either success or error+reason
571 static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset
,
574 u32 ret_payload
[PAYLOAD_ARG_CNT
];
580 ret
= zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS
, reset
, 0,
582 *status
= ret_payload
[1];
588 * zynqmp_pm_fpga_load - Perform the fpga load
589 * @address: Address to write to
590 * @size: pl bitstream size
591 * @flags: Bitstream type
592 * -XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
593 * -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
595 * This function provides access to pmufw. To transfer
596 * the required bitstream into PL.
598 * Return: Returns status, either success or error+reason
600 static int zynqmp_pm_fpga_load(const u64 address
, const u32 size
,
603 return zynqmp_pm_invoke_fn(PM_FPGA_LOAD
, lower_32_bits(address
),
604 upper_32_bits(address
), size
, flags
, NULL
);
608 * zynqmp_pm_fpga_get_status - Read value from PCAP status register
609 * @value: Value to read
611 * This function provides access to the pmufw to get the PCAP
614 * Return: Returns status, either success or error+reason
616 static int zynqmp_pm_fpga_get_status(u32
*value
)
618 u32 ret_payload
[PAYLOAD_ARG_CNT
];
624 ret
= zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS
, 0, 0, 0, 0, ret_payload
);
625 *value
= ret_payload
[1];
631 * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
632 * master has initialized its own power management
634 * This API function is to be used for notify the power management controller
635 * about the completed power management initialization.
637 * Return: Returns status, either success or error+reason
639 static int zynqmp_pm_init_finalize(void)
641 return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE
, 0, 0, 0, 0, NULL
);
645 * zynqmp_pm_set_suspend_mode() - Set system suspend mode
646 * @mode: Mode to set for system suspend
648 * This API function is used to set mode of system suspend.
650 * Return: Returns status, either success or error+reason
652 static int zynqmp_pm_set_suspend_mode(u32 mode
)
654 return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE
, mode
, 0, 0, 0, NULL
);
658 * zynqmp_pm_request_node() - Request a node with specific capabilities
659 * @node: Node ID of the slave
660 * @capabilities: Requested capabilities of the slave
661 * @qos: Quality of service (not supported)
662 * @ack: Flag to specify whether acknowledge is requested
664 * This function is used by master to request particular node from firmware.
665 * Every master must request node before using it.
667 * Return: Returns status, either success or error+reason
669 static int zynqmp_pm_request_node(const u32 node
, const u32 capabilities
,
671 const enum zynqmp_pm_request_ack ack
)
673 return zynqmp_pm_invoke_fn(PM_REQUEST_NODE
, node
, capabilities
,
678 * zynqmp_pm_release_node() - Release a node
679 * @node: Node ID of the slave
681 * This function is used by master to inform firmware that master
682 * has released node. Once released, master must not use that node
683 * without re-request.
685 * Return: Returns status, either success or error+reason
687 static int zynqmp_pm_release_node(const u32 node
)
689 return zynqmp_pm_invoke_fn(PM_RELEASE_NODE
, node
, 0, 0, 0, NULL
);
693 * zynqmp_pm_set_requirement() - PM call to set requirement for PM slaves
694 * @node: Node ID of the slave
695 * @capabilities: Requested capabilities of the slave
696 * @qos: Quality of service (not supported)
697 * @ack: Flag to specify whether acknowledge is requested
699 * This API function is to be used for slaves a PU already has requested
700 * to change its capabilities.
702 * Return: Returns status, either success or error+reason
704 static int zynqmp_pm_set_requirement(const u32 node
, const u32 capabilities
,
706 const enum zynqmp_pm_request_ack ack
)
708 return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT
, node
, capabilities
,
713 * zynqmp_pm_aes - Access AES hardware to encrypt/decrypt the data using
715 * @address: Address of the AesParams structure.
716 * @out: Returned output value
718 * Return: Returns status, either success or error code.
720 static int zynqmp_pm_aes_engine(const u64 address
, u32
*out
)
722 u32 ret_payload
[PAYLOAD_ARG_CNT
];
728 ret
= zynqmp_pm_invoke_fn(PM_SECURE_AES
, upper_32_bits(address
),
729 lower_32_bits(address
),
731 *out
= ret_payload
[1];
736 static const struct zynqmp_eemi_ops eemi_ops
= {
737 .get_api_version
= zynqmp_pm_get_api_version
,
738 .get_chipid
= zynqmp_pm_get_chipid
,
739 .query_data
= zynqmp_pm_query_data
,
740 .clock_enable
= zynqmp_pm_clock_enable
,
741 .clock_disable
= zynqmp_pm_clock_disable
,
742 .clock_getstate
= zynqmp_pm_clock_getstate
,
743 .clock_setdivider
= zynqmp_pm_clock_setdivider
,
744 .clock_getdivider
= zynqmp_pm_clock_getdivider
,
745 .clock_setrate
= zynqmp_pm_clock_setrate
,
746 .clock_getrate
= zynqmp_pm_clock_getrate
,
747 .clock_setparent
= zynqmp_pm_clock_setparent
,
748 .clock_getparent
= zynqmp_pm_clock_getparent
,
749 .ioctl
= zynqmp_pm_ioctl
,
750 .reset_assert
= zynqmp_pm_reset_assert
,
751 .reset_get_status
= zynqmp_pm_reset_get_status
,
752 .init_finalize
= zynqmp_pm_init_finalize
,
753 .set_suspend_mode
= zynqmp_pm_set_suspend_mode
,
754 .request_node
= zynqmp_pm_request_node
,
755 .release_node
= zynqmp_pm_release_node
,
756 .set_requirement
= zynqmp_pm_set_requirement
,
757 .fpga_load
= zynqmp_pm_fpga_load
,
758 .fpga_get_status
= zynqmp_pm_fpga_get_status
,
759 .aes
= zynqmp_pm_aes_engine
,
763 * zynqmp_pm_get_eemi_ops - Get eemi ops functions
765 * Return: Pointer of eemi_ops structure
767 const struct zynqmp_eemi_ops
*zynqmp_pm_get_eemi_ops(void)
772 return ERR_PTR(-EPROBE_DEFER
);
775 EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops
);
777 static int zynqmp_firmware_probe(struct platform_device
*pdev
)
779 struct device
*dev
= &pdev
->dev
;
780 struct device_node
*np
;
783 np
= of_find_compatible_node(NULL
, NULL
, "xlnx,zynqmp");
785 np
= of_find_compatible_node(NULL
, NULL
, "xlnx,versal");
789 feature_check_enabled
= true;
793 ret
= get_set_conduit_method(dev
->of_node
);
797 /* Check PM API version number */
798 zynqmp_pm_get_api_version(&pm_api_version
);
799 if (pm_api_version
< ZYNQMP_PM_VERSION
) {
800 panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",
802 ZYNQMP_PM_VERSION_MAJOR
, ZYNQMP_PM_VERSION_MINOR
,
803 pm_api_version
>> 16, pm_api_version
& 0xFFFF);
806 pr_info("%s Platform Management API v%d.%d\n", __func__
,
807 pm_api_version
>> 16, pm_api_version
& 0xFFFF);
809 /* Check trustzone version number */
810 ret
= zynqmp_pm_get_trustzone_version(&pm_tz_version
);
812 panic("Legacy trustzone found without version support\n");
814 if (pm_tz_version
< ZYNQMP_TZ_VERSION
)
815 panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",
817 ZYNQMP_TZ_VERSION_MAJOR
, ZYNQMP_TZ_VERSION_MINOR
,
818 pm_tz_version
>> 16, pm_tz_version
& 0xFFFF);
820 pr_info("%s Trustzone version v%d.%d\n", __func__
,
821 pm_tz_version
>> 16, pm_tz_version
& 0xFFFF);
823 /* Assign eemi_ops_table */
824 eemi_ops_tbl
= &eemi_ops
;
826 zynqmp_pm_api_debugfs_init();
828 ret
= mfd_add_devices(&pdev
->dev
, PLATFORM_DEVID_NONE
, firmware_devs
,
829 ARRAY_SIZE(firmware_devs
), NULL
, 0, NULL
);
831 dev_err(&pdev
->dev
, "failed to add MFD devices %d\n", ret
);
835 return of_platform_populate(dev
->of_node
, NULL
, NULL
, dev
);
838 static int zynqmp_firmware_remove(struct platform_device
*pdev
)
840 mfd_remove_devices(&pdev
->dev
);
841 zynqmp_pm_api_debugfs_exit();
846 static const struct of_device_id zynqmp_firmware_of_match
[] = {
847 {.compatible
= "xlnx,zynqmp-firmware"},
848 {.compatible
= "xlnx,versal-firmware"},
851 MODULE_DEVICE_TABLE(of
, zynqmp_firmware_of_match
);
853 static struct platform_driver zynqmp_firmware_driver
= {
855 .name
= "zynqmp_firmware",
856 .of_match_table
= zynqmp_firmware_of_match
,
858 .probe
= zynqmp_firmware_probe
,
859 .remove
= zynqmp_firmware_remove
,
861 module_platform_driver(zynqmp_firmware_driver
);