xref: /openbmc/linux/drivers/firmware/xilinx/zynqmp.c (revision bc3843d4)
176582671SRajan Vaja // SPDX-License-Identifier: GPL-2.0
276582671SRajan Vaja /*
376582671SRajan Vaja  * Xilinx Zynq MPSoC Firmware layer
476582671SRajan Vaja  *
576582671SRajan Vaja  *  Copyright (C) 2014-2018 Xilinx, Inc.
676582671SRajan Vaja  *
776582671SRajan Vaja  *  Michal Simek <michal.simek@xilinx.com>
876582671SRajan Vaja  *  Davorin Mista <davorin.mista@aggios.com>
976582671SRajan Vaja  *  Jolly Shah <jollys@xilinx.com>
1076582671SRajan Vaja  *  Rajan Vaja <rajanv@xilinx.com>
1176582671SRajan Vaja  */
1276582671SRajan Vaja 
1376582671SRajan Vaja #include <linux/arm-smccc.h>
1476582671SRajan Vaja #include <linux/compiler.h>
1576582671SRajan Vaja #include <linux/device.h>
1676582671SRajan Vaja #include <linux/init.h>
1776582671SRajan Vaja #include <linux/module.h>
1876582671SRajan Vaja #include <linux/of.h>
1976582671SRajan Vaja #include <linux/of_platform.h>
2076582671SRajan Vaja #include <linux/slab.h>
2176582671SRajan Vaja #include <linux/uaccess.h>
2276582671SRajan Vaja 
2376582671SRajan Vaja #include <linux/firmware/xlnx-zynqmp.h>
24b3217252SRajan Vaja #include "zynqmp-debug.h"
2576582671SRajan Vaja 
2676582671SRajan Vaja /**
2776582671SRajan Vaja  * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
2876582671SRajan Vaja  * @ret_status:		PMUFW return code
2976582671SRajan Vaja  *
3076582671SRajan Vaja  * Return: corresponding Linux error code
3176582671SRajan Vaja  */
3276582671SRajan Vaja static int zynqmp_pm_ret_code(u32 ret_status)
3376582671SRajan Vaja {
3476582671SRajan Vaja 	switch (ret_status) {
3576582671SRajan Vaja 	case XST_PM_SUCCESS:
3676582671SRajan Vaja 	case XST_PM_DOUBLE_REQ:
3776582671SRajan Vaja 		return 0;
3876582671SRajan Vaja 	case XST_PM_NO_ACCESS:
3976582671SRajan Vaja 		return -EACCES;
4076582671SRajan Vaja 	case XST_PM_ABORT_SUSPEND:
4176582671SRajan Vaja 		return -ECANCELED;
4276582671SRajan Vaja 	case XST_PM_INTERNAL:
4376582671SRajan Vaja 	case XST_PM_CONFLICT:
4476582671SRajan Vaja 	case XST_PM_INVALID_NODE:
4576582671SRajan Vaja 	default:
4676582671SRajan Vaja 		return -EINVAL;
4776582671SRajan Vaja 	}
4876582671SRajan Vaja }
4976582671SRajan Vaja 
5076582671SRajan Vaja static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
5176582671SRajan Vaja 				    u32 *ret_payload)
5276582671SRajan Vaja {
5376582671SRajan Vaja 	return -ENODEV;
5476582671SRajan Vaja }
5576582671SRajan Vaja 
5676582671SRajan Vaja /*
5776582671SRajan Vaja  * PM function call wrapper
5876582671SRajan Vaja  * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
5976582671SRajan Vaja  */
6076582671SRajan Vaja static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
6176582671SRajan Vaja 
6276582671SRajan Vaja /**
6376582671SRajan Vaja  * do_fw_call_smc() - Call system-level platform management layer (SMC)
6476582671SRajan Vaja  * @arg0:		Argument 0 to SMC call
6576582671SRajan Vaja  * @arg1:		Argument 1 to SMC call
6676582671SRajan Vaja  * @arg2:		Argument 2 to SMC call
6776582671SRajan Vaja  * @ret_payload:	Returned value array
6876582671SRajan Vaja  *
6976582671SRajan Vaja  * Invoke platform management function via SMC call (no hypervisor present).
7076582671SRajan Vaja  *
7176582671SRajan Vaja  * Return: Returns status, either success or error+reason
7276582671SRajan Vaja  */
7376582671SRajan Vaja static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
7476582671SRajan Vaja 				   u32 *ret_payload)
7576582671SRajan Vaja {
7676582671SRajan Vaja 	struct arm_smccc_res res;
7776582671SRajan Vaja 
7876582671SRajan Vaja 	arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
7976582671SRajan Vaja 
8076582671SRajan Vaja 	if (ret_payload) {
8176582671SRajan Vaja 		ret_payload[0] = lower_32_bits(res.a0);
8276582671SRajan Vaja 		ret_payload[1] = upper_32_bits(res.a0);
8376582671SRajan Vaja 		ret_payload[2] = lower_32_bits(res.a1);
8476582671SRajan Vaja 		ret_payload[3] = upper_32_bits(res.a1);
8576582671SRajan Vaja 	}
8676582671SRajan Vaja 
8776582671SRajan Vaja 	return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
8876582671SRajan Vaja }
8976582671SRajan Vaja 
9076582671SRajan Vaja /**
9176582671SRajan Vaja  * do_fw_call_hvc() - Call system-level platform management layer (HVC)
9276582671SRajan Vaja  * @arg0:		Argument 0 to HVC call
9376582671SRajan Vaja  * @arg1:		Argument 1 to HVC call
9476582671SRajan Vaja  * @arg2:		Argument 2 to HVC call
9576582671SRajan Vaja  * @ret_payload:	Returned value array
9676582671SRajan Vaja  *
9776582671SRajan Vaja  * Invoke platform management function via HVC
9876582671SRajan Vaja  * HVC-based for communication through hypervisor
9976582671SRajan Vaja  * (no direct communication with ATF).
10076582671SRajan Vaja  *
10176582671SRajan Vaja  * Return: Returns status, either success or error+reason
10276582671SRajan Vaja  */
10376582671SRajan Vaja static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
10476582671SRajan Vaja 				   u32 *ret_payload)
10576582671SRajan Vaja {
10676582671SRajan Vaja 	struct arm_smccc_res res;
10776582671SRajan Vaja 
10876582671SRajan Vaja 	arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
10976582671SRajan Vaja 
11076582671SRajan Vaja 	if (ret_payload) {
11176582671SRajan Vaja 		ret_payload[0] = lower_32_bits(res.a0);
11276582671SRajan Vaja 		ret_payload[1] = upper_32_bits(res.a0);
11376582671SRajan Vaja 		ret_payload[2] = lower_32_bits(res.a1);
11476582671SRajan Vaja 		ret_payload[3] = upper_32_bits(res.a1);
11576582671SRajan Vaja 	}
11676582671SRajan Vaja 
11776582671SRajan Vaja 	return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
11876582671SRajan Vaja }
11976582671SRajan Vaja 
12076582671SRajan Vaja /**
12176582671SRajan Vaja  * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
12276582671SRajan Vaja  *			   caller function depending on the configuration
12376582671SRajan Vaja  * @pm_api_id:		Requested PM-API call
12476582671SRajan Vaja  * @arg0:		Argument 0 to requested PM-API call
12576582671SRajan Vaja  * @arg1:		Argument 1 to requested PM-API call
12676582671SRajan Vaja  * @arg2:		Argument 2 to requested PM-API call
12776582671SRajan Vaja  * @arg3:		Argument 3 to requested PM-API call
12876582671SRajan Vaja  * @ret_payload:	Returned value array
12976582671SRajan Vaja  *
13076582671SRajan Vaja  * Invoke platform management function for SMC or HVC call, depending on
13176582671SRajan Vaja  * configuration.
13276582671SRajan Vaja  * Following SMC Calling Convention (SMCCC) for SMC64:
13376582671SRajan Vaja  * Pm Function Identifier,
13476582671SRajan Vaja  * PM_SIP_SVC + PM_API_ID =
13576582671SRajan Vaja  *	((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
13676582671SRajan Vaja  *	((SMC_64) << FUNCID_CC_SHIFT)
13776582671SRajan Vaja  *	((SIP_START) << FUNCID_OEN_SHIFT)
13876582671SRajan Vaja  *	((PM_API_ID) & FUNCID_NUM_MASK))
13976582671SRajan Vaja  *
14076582671SRajan Vaja  * PM_SIP_SVC	- Registered ZynqMP SIP Service Call.
14176582671SRajan Vaja  * PM_API_ID	- Platform Management API ID.
14276582671SRajan Vaja  *
14376582671SRajan Vaja  * Return: Returns status, either success or error+reason
14476582671SRajan Vaja  */
14576582671SRajan Vaja int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
14676582671SRajan Vaja 			u32 arg2, u32 arg3, u32 *ret_payload)
14776582671SRajan Vaja {
14876582671SRajan Vaja 	/*
14976582671SRajan Vaja 	 * Added SIP service call Function Identifier
15076582671SRajan Vaja 	 * Make sure to stay in x0 register
15176582671SRajan Vaja 	 */
15276582671SRajan Vaja 	u64 smc_arg[4];
15376582671SRajan Vaja 
15476582671SRajan Vaja 	smc_arg[0] = PM_SIP_SVC | pm_api_id;
15576582671SRajan Vaja 	smc_arg[1] = ((u64)arg1 << 32) | arg0;
15676582671SRajan Vaja 	smc_arg[2] = ((u64)arg3 << 32) | arg2;
15776582671SRajan Vaja 
15876582671SRajan Vaja 	return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
15976582671SRajan Vaja }
16076582671SRajan Vaja 
16176582671SRajan Vaja static u32 pm_api_version;
16276582671SRajan Vaja static u32 pm_tz_version;
16376582671SRajan Vaja 
16476582671SRajan Vaja /**
16576582671SRajan Vaja  * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
16676582671SRajan Vaja  * @version:	Returned version value
16776582671SRajan Vaja  *
16876582671SRajan Vaja  * Return: Returns status, either success or error+reason
16976582671SRajan Vaja  */
17076582671SRajan Vaja static int zynqmp_pm_get_api_version(u32 *version)
17176582671SRajan Vaja {
17276582671SRajan Vaja 	u32 ret_payload[PAYLOAD_ARG_CNT];
17376582671SRajan Vaja 	int ret;
17476582671SRajan Vaja 
17576582671SRajan Vaja 	if (!version)
17676582671SRajan Vaja 		return -EINVAL;
17776582671SRajan Vaja 
17876582671SRajan Vaja 	/* Check is PM API version already verified */
17976582671SRajan Vaja 	if (pm_api_version > 0) {
18076582671SRajan Vaja 		*version = pm_api_version;
18176582671SRajan Vaja 		return 0;
18276582671SRajan Vaja 	}
18376582671SRajan Vaja 	ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload);
18476582671SRajan Vaja 	*version = ret_payload[1];
18576582671SRajan Vaja 
18676582671SRajan Vaja 	return ret;
18776582671SRajan Vaja }
18876582671SRajan Vaja 
18976582671SRajan Vaja /**
19076582671SRajan Vaja  * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
19176582671SRajan Vaja  * @version:	Returned version value
19276582671SRajan Vaja  *
19376582671SRajan Vaja  * Return: Returns status, either success or error+reason
19476582671SRajan Vaja  */
19576582671SRajan Vaja static int zynqmp_pm_get_trustzone_version(u32 *version)
19676582671SRajan Vaja {
19776582671SRajan Vaja 	u32 ret_payload[PAYLOAD_ARG_CNT];
19876582671SRajan Vaja 	int ret;
19976582671SRajan Vaja 
20076582671SRajan Vaja 	if (!version)
20176582671SRajan Vaja 		return -EINVAL;
20276582671SRajan Vaja 
20376582671SRajan Vaja 	/* Check is PM trustzone version already verified */
20476582671SRajan Vaja 	if (pm_tz_version > 0) {
20576582671SRajan Vaja 		*version = pm_tz_version;
20676582671SRajan Vaja 		return 0;
20776582671SRajan Vaja 	}
20876582671SRajan Vaja 	ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0,
20976582671SRajan Vaja 				  0, 0, ret_payload);
21076582671SRajan Vaja 	*version = ret_payload[1];
21176582671SRajan Vaja 
21276582671SRajan Vaja 	return ret;
21376582671SRajan Vaja }
21476582671SRajan Vaja 
21576582671SRajan Vaja /**
21676582671SRajan Vaja  * get_set_conduit_method() - Choose SMC or HVC based communication
21776582671SRajan Vaja  * @np:		Pointer to the device_node structure
21876582671SRajan Vaja  *
21976582671SRajan Vaja  * Use SMC or HVC-based functions to communicate with EL2/EL3.
22076582671SRajan Vaja  *
22176582671SRajan Vaja  * Return: Returns 0 on success or error code
22276582671SRajan Vaja  */
22376582671SRajan Vaja static int get_set_conduit_method(struct device_node *np)
22476582671SRajan Vaja {
22576582671SRajan Vaja 	const char *method;
22676582671SRajan Vaja 
22776582671SRajan Vaja 	if (of_property_read_string(np, "method", &method)) {
22876582671SRajan Vaja 		pr_warn("%s missing \"method\" property\n", __func__);
22976582671SRajan Vaja 		return -ENXIO;
23076582671SRajan Vaja 	}
23176582671SRajan Vaja 
23276582671SRajan Vaja 	if (!strcmp("hvc", method)) {
23376582671SRajan Vaja 		do_fw_call = do_fw_call_hvc;
23476582671SRajan Vaja 	} else if (!strcmp("smc", method)) {
23576582671SRajan Vaja 		do_fw_call = do_fw_call_smc;
23676582671SRajan Vaja 	} else {
23776582671SRajan Vaja 		pr_warn("%s Invalid \"method\" property: %s\n",
23876582671SRajan Vaja 			__func__, method);
23976582671SRajan Vaja 		return -EINVAL;
24076582671SRajan Vaja 	}
24176582671SRajan Vaja 
24276582671SRajan Vaja 	return 0;
24376582671SRajan Vaja }
24476582671SRajan Vaja 
24559ecdd77SRajan Vaja /**
24659ecdd77SRajan Vaja  * zynqmp_pm_query_data() - Get query data from firmware
24759ecdd77SRajan Vaja  * @qdata:	Variable to the zynqmp_pm_query_data structure
24859ecdd77SRajan Vaja  * @out:	Returned output value
24959ecdd77SRajan Vaja  *
25059ecdd77SRajan Vaja  * Return: Returns status, either success or error+reason
25159ecdd77SRajan Vaja  */
25259ecdd77SRajan Vaja static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
25359ecdd77SRajan Vaja {
254f9627312SRajan Vaja 	int ret;
255f9627312SRajan Vaja 
256f9627312SRajan Vaja 	ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
25759ecdd77SRajan Vaja 				  qdata.arg2, qdata.arg3, out);
258f9627312SRajan Vaja 
259f9627312SRajan Vaja 	/*
260f9627312SRajan Vaja 	 * For clock name query, all bytes in SMC response are clock name
261f9627312SRajan Vaja 	 * characters and return code is always success. For invalid clocks,
262f9627312SRajan Vaja 	 * clock name bytes would be zeros.
263f9627312SRajan Vaja 	 */
264f9627312SRajan Vaja 	return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
265f9627312SRajan Vaja }
266f9627312SRajan Vaja 
267f9627312SRajan Vaja /**
268f9627312SRajan Vaja  * zynqmp_pm_clock_enable() - Enable the clock for given id
269f9627312SRajan Vaja  * @clock_id:	ID of the clock to be enabled
270f9627312SRajan Vaja  *
271f9627312SRajan Vaja  * This function is used by master to enable the clock
272f9627312SRajan Vaja  * including peripherals and PLL clocks.
273f9627312SRajan Vaja  *
274f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
275f9627312SRajan Vaja  */
276f9627312SRajan Vaja static int zynqmp_pm_clock_enable(u32 clock_id)
277f9627312SRajan Vaja {
278f9627312SRajan Vaja 	return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
279f9627312SRajan Vaja }
280f9627312SRajan Vaja 
281f9627312SRajan Vaja /**
282f9627312SRajan Vaja  * zynqmp_pm_clock_disable() - Disable the clock for given id
283f9627312SRajan Vaja  * @clock_id:	ID of the clock to be disable
284f9627312SRajan Vaja  *
285f9627312SRajan Vaja  * This function is used by master to disable the clock
286f9627312SRajan Vaja  * including peripherals and PLL clocks.
287f9627312SRajan Vaja  *
288f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
289f9627312SRajan Vaja  */
290f9627312SRajan Vaja static int zynqmp_pm_clock_disable(u32 clock_id)
291f9627312SRajan Vaja {
292f9627312SRajan Vaja 	return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
293f9627312SRajan Vaja }
294f9627312SRajan Vaja 
295f9627312SRajan Vaja /**
296f9627312SRajan Vaja  * zynqmp_pm_clock_getstate() - Get the clock state for given id
297f9627312SRajan Vaja  * @clock_id:	ID of the clock to be queried
298f9627312SRajan Vaja  * @state:	1/0 (Enabled/Disabled)
299f9627312SRajan Vaja  *
300f9627312SRajan Vaja  * This function is used by master to get the state of clock
301f9627312SRajan Vaja  * including peripherals and PLL clocks.
302f9627312SRajan Vaja  *
303f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
304f9627312SRajan Vaja  */
305f9627312SRajan Vaja static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
306f9627312SRajan Vaja {
307f9627312SRajan Vaja 	u32 ret_payload[PAYLOAD_ARG_CNT];
308f9627312SRajan Vaja 	int ret;
309f9627312SRajan Vaja 
310f9627312SRajan Vaja 	ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
311f9627312SRajan Vaja 				  0, 0, ret_payload);
312f9627312SRajan Vaja 	*state = ret_payload[1];
313f9627312SRajan Vaja 
314f9627312SRajan Vaja 	return ret;
315f9627312SRajan Vaja }
316f9627312SRajan Vaja 
317f9627312SRajan Vaja /**
318f9627312SRajan Vaja  * zynqmp_pm_clock_setdivider() - Set the clock divider for given id
319f9627312SRajan Vaja  * @clock_id:	ID of the clock
320f9627312SRajan Vaja  * @divider:	divider value
321f9627312SRajan Vaja  *
322f9627312SRajan Vaja  * This function is used by master to set divider for any clock
323f9627312SRajan Vaja  * to achieve desired rate.
324f9627312SRajan Vaja  *
325f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
326f9627312SRajan Vaja  */
327f9627312SRajan Vaja static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
328f9627312SRajan Vaja {
329f9627312SRajan Vaja 	return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
330f9627312SRajan Vaja 				   0, 0, NULL);
331f9627312SRajan Vaja }
332f9627312SRajan Vaja 
333f9627312SRajan Vaja /**
334f9627312SRajan Vaja  * zynqmp_pm_clock_getdivider() - Get the clock divider for given id
335f9627312SRajan Vaja  * @clock_id:	ID of the clock
336f9627312SRajan Vaja  * @divider:	divider value
337f9627312SRajan Vaja  *
338f9627312SRajan Vaja  * This function is used by master to get divider values
339f9627312SRajan Vaja  * for any clock.
340f9627312SRajan Vaja  *
341f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
342f9627312SRajan Vaja  */
343f9627312SRajan Vaja static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
344f9627312SRajan Vaja {
345f9627312SRajan Vaja 	u32 ret_payload[PAYLOAD_ARG_CNT];
346f9627312SRajan Vaja 	int ret;
347f9627312SRajan Vaja 
348f9627312SRajan Vaja 	ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
349f9627312SRajan Vaja 				  0, 0, ret_payload);
350f9627312SRajan Vaja 	*divider = ret_payload[1];
351f9627312SRajan Vaja 
352f9627312SRajan Vaja 	return ret;
353f9627312SRajan Vaja }
354f9627312SRajan Vaja 
355f9627312SRajan Vaja /**
356f9627312SRajan Vaja  * zynqmp_pm_clock_setrate() - Set the clock rate for given id
357f9627312SRajan Vaja  * @clock_id:	ID of the clock
358f9627312SRajan Vaja  * @rate:	rate value in hz
359f9627312SRajan Vaja  *
360f9627312SRajan Vaja  * This function is used by master to set rate for any clock.
361f9627312SRajan Vaja  *
362f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
363f9627312SRajan Vaja  */
364f9627312SRajan Vaja static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
365f9627312SRajan Vaja {
366f9627312SRajan Vaja 	return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
367f9627312SRajan Vaja 				   lower_32_bits(rate),
368f9627312SRajan Vaja 				   upper_32_bits(rate),
369f9627312SRajan Vaja 				   0, NULL);
370f9627312SRajan Vaja }
371f9627312SRajan Vaja 
372f9627312SRajan Vaja /**
373f9627312SRajan Vaja  * zynqmp_pm_clock_getrate() - Get the clock rate for given id
374f9627312SRajan Vaja  * @clock_id:	ID of the clock
375f9627312SRajan Vaja  * @rate:	rate value in hz
376f9627312SRajan Vaja  *
377f9627312SRajan Vaja  * This function is used by master to get rate
378f9627312SRajan Vaja  * for any clock.
379f9627312SRajan Vaja  *
380f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
381f9627312SRajan Vaja  */
382f9627312SRajan Vaja static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
383f9627312SRajan Vaja {
384f9627312SRajan Vaja 	u32 ret_payload[PAYLOAD_ARG_CNT];
385f9627312SRajan Vaja 	int ret;
386f9627312SRajan Vaja 
387f9627312SRajan Vaja 	ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
388f9627312SRajan Vaja 				  0, 0, ret_payload);
389f9627312SRajan Vaja 	*rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
390f9627312SRajan Vaja 
391f9627312SRajan Vaja 	return ret;
392f9627312SRajan Vaja }
393f9627312SRajan Vaja 
394f9627312SRajan Vaja /**
395f9627312SRajan Vaja  * zynqmp_pm_clock_setparent() - Set the clock parent for given id
396f9627312SRajan Vaja  * @clock_id:	ID of the clock
397f9627312SRajan Vaja  * @parent_id:	parent id
398f9627312SRajan Vaja  *
399f9627312SRajan Vaja  * This function is used by master to set parent for any clock.
400f9627312SRajan Vaja  *
401f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
402f9627312SRajan Vaja  */
403f9627312SRajan Vaja static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
404f9627312SRajan Vaja {
405f9627312SRajan Vaja 	return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
406f9627312SRajan Vaja 				   parent_id, 0, 0, NULL);
407f9627312SRajan Vaja }
408f9627312SRajan Vaja 
409f9627312SRajan Vaja /**
410f9627312SRajan Vaja  * zynqmp_pm_clock_getparent() - Get the clock parent for given id
411f9627312SRajan Vaja  * @clock_id:	ID of the clock
412f9627312SRajan Vaja  * @parent_id:	parent id
413f9627312SRajan Vaja  *
414f9627312SRajan Vaja  * This function is used by master to get parent index
415f9627312SRajan Vaja  * for any clock.
416f9627312SRajan Vaja  *
417f9627312SRajan Vaja  * Return: Returns status, either success or error+reason
418f9627312SRajan Vaja  */
419f9627312SRajan Vaja static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
420f9627312SRajan Vaja {
421f9627312SRajan Vaja 	u32 ret_payload[PAYLOAD_ARG_CNT];
422f9627312SRajan Vaja 	int ret;
423f9627312SRajan Vaja 
424f9627312SRajan Vaja 	ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
425f9627312SRajan Vaja 				  0, 0, ret_payload);
426f9627312SRajan Vaja 	*parent_id = ret_payload[1];
427f9627312SRajan Vaja 
428f9627312SRajan Vaja 	return ret;
42959ecdd77SRajan Vaja }
43059ecdd77SRajan Vaja 
4313b0296b8SRajan Vaja /**
4323b0296b8SRajan Vaja  * zynqmp_is_valid_ioctl() - Check whether IOCTL ID is valid or not
4333b0296b8SRajan Vaja  * @ioctl_id:	IOCTL ID
4343b0296b8SRajan Vaja  *
4353b0296b8SRajan Vaja  * Return: 1 if IOCTL is valid else 0
4363b0296b8SRajan Vaja  */
4373b0296b8SRajan Vaja static inline int zynqmp_is_valid_ioctl(u32 ioctl_id)
4383b0296b8SRajan Vaja {
4393b0296b8SRajan Vaja 	switch (ioctl_id) {
4403b0296b8SRajan Vaja 	case IOCTL_SET_PLL_FRAC_MODE:
4413b0296b8SRajan Vaja 	case IOCTL_GET_PLL_FRAC_MODE:
4423b0296b8SRajan Vaja 	case IOCTL_SET_PLL_FRAC_DATA:
4433b0296b8SRajan Vaja 	case IOCTL_GET_PLL_FRAC_DATA:
4443b0296b8SRajan Vaja 		return 1;
4453b0296b8SRajan Vaja 	default:
4463b0296b8SRajan Vaja 		return 0;
4473b0296b8SRajan Vaja 	}
4483b0296b8SRajan Vaja }
4493b0296b8SRajan Vaja 
4503b0296b8SRajan Vaja /**
4513b0296b8SRajan Vaja  * zynqmp_pm_ioctl() - PM IOCTL API for device control and configs
4523b0296b8SRajan Vaja  * @node_id:	Node ID of the device
4533b0296b8SRajan Vaja  * @ioctl_id:	ID of the requested IOCTL
4543b0296b8SRajan Vaja  * @arg1:	Argument 1 to requested IOCTL call
4553b0296b8SRajan Vaja  * @arg2:	Argument 2 to requested IOCTL call
4563b0296b8SRajan Vaja  * @out:	Returned output value
4573b0296b8SRajan Vaja  *
4583b0296b8SRajan Vaja  * This function calls IOCTL to firmware for device control and configuration.
4593b0296b8SRajan Vaja  *
4603b0296b8SRajan Vaja  * Return: Returns status, either success or error+reason
4613b0296b8SRajan Vaja  */
4623b0296b8SRajan Vaja static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
4633b0296b8SRajan Vaja 			   u32 *out)
4643b0296b8SRajan Vaja {
4653b0296b8SRajan Vaja 	if (!zynqmp_is_valid_ioctl(ioctl_id))
4663b0296b8SRajan Vaja 		return -EINVAL;
4673b0296b8SRajan Vaja 
4683b0296b8SRajan Vaja 	return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, ioctl_id,
4693b0296b8SRajan Vaja 				   arg1, arg2, out);
4703b0296b8SRajan Vaja }
4713b0296b8SRajan Vaja 
472bc3843d4SNava kishore Manne /**
473bc3843d4SNava kishore Manne  * zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release)
474bc3843d4SNava kishore Manne  * @reset:		Reset to be configured
475bc3843d4SNava kishore Manne  * @assert_flag:	Flag stating should reset be asserted (1) or
476bc3843d4SNava kishore Manne  *			released (0)
477bc3843d4SNava kishore Manne  *
478bc3843d4SNava kishore Manne  * Return: Returns status, either success or error+reason
479bc3843d4SNava kishore Manne  */
480bc3843d4SNava kishore Manne static int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,
481bc3843d4SNava kishore Manne 				  const enum zynqmp_pm_reset_action assert_flag)
482bc3843d4SNava kishore Manne {
483bc3843d4SNava kishore Manne 	return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, reset, assert_flag,
484bc3843d4SNava kishore Manne 				   0, 0, NULL);
485bc3843d4SNava kishore Manne }
486bc3843d4SNava kishore Manne 
487bc3843d4SNava kishore Manne /**
488bc3843d4SNava kishore Manne  * zynqmp_pm_reset_get_status - Get status of the reset
489bc3843d4SNava kishore Manne  * @reset:      Reset whose status should be returned
490bc3843d4SNava kishore Manne  * @status:     Returned status
491bc3843d4SNava kishore Manne  *
492bc3843d4SNava kishore Manne  * Return: Returns status, either success or error+reason
493bc3843d4SNava kishore Manne  */
494bc3843d4SNava kishore Manne static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
495bc3843d4SNava kishore Manne 				      u32 *status)
496bc3843d4SNava kishore Manne {
497bc3843d4SNava kishore Manne 	u32 ret_payload[PAYLOAD_ARG_CNT];
498bc3843d4SNava kishore Manne 	int ret;
499bc3843d4SNava kishore Manne 
500bc3843d4SNava kishore Manne 	if (!status)
501bc3843d4SNava kishore Manne 		return -EINVAL;
502bc3843d4SNava kishore Manne 
503bc3843d4SNava kishore Manne 	ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, reset, 0,
504bc3843d4SNava kishore Manne 				  0, 0, ret_payload);
505bc3843d4SNava kishore Manne 	*status = ret_payload[1];
506bc3843d4SNava kishore Manne 
507bc3843d4SNava kishore Manne 	return ret;
508bc3843d4SNava kishore Manne }
509bc3843d4SNava kishore Manne 
51076582671SRajan Vaja static const struct zynqmp_eemi_ops eemi_ops = {
51176582671SRajan Vaja 	.get_api_version = zynqmp_pm_get_api_version,
51259ecdd77SRajan Vaja 	.query_data = zynqmp_pm_query_data,
513f9627312SRajan Vaja 	.clock_enable = zynqmp_pm_clock_enable,
514f9627312SRajan Vaja 	.clock_disable = zynqmp_pm_clock_disable,
515f9627312SRajan Vaja 	.clock_getstate = zynqmp_pm_clock_getstate,
516f9627312SRajan Vaja 	.clock_setdivider = zynqmp_pm_clock_setdivider,
517f9627312SRajan Vaja 	.clock_getdivider = zynqmp_pm_clock_getdivider,
518f9627312SRajan Vaja 	.clock_setrate = zynqmp_pm_clock_setrate,
519f9627312SRajan Vaja 	.clock_getrate = zynqmp_pm_clock_getrate,
520f9627312SRajan Vaja 	.clock_setparent = zynqmp_pm_clock_setparent,
521f9627312SRajan Vaja 	.clock_getparent = zynqmp_pm_clock_getparent,
5223b0296b8SRajan Vaja 	.ioctl = zynqmp_pm_ioctl,
523bc3843d4SNava kishore Manne 	.reset_assert = zynqmp_pm_reset_assert,
524bc3843d4SNava kishore Manne 	.reset_get_status = zynqmp_pm_reset_get_status,
52576582671SRajan Vaja };
52676582671SRajan Vaja 
52776582671SRajan Vaja /**
52876582671SRajan Vaja  * zynqmp_pm_get_eemi_ops - Get eemi ops functions
52976582671SRajan Vaja  *
53076582671SRajan Vaja  * Return: Pointer of eemi_ops structure
53176582671SRajan Vaja  */
53276582671SRajan Vaja const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
53376582671SRajan Vaja {
53476582671SRajan Vaja 	return &eemi_ops;
53576582671SRajan Vaja }
53676582671SRajan Vaja EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
53776582671SRajan Vaja 
53876582671SRajan Vaja static int zynqmp_firmware_probe(struct platform_device *pdev)
53976582671SRajan Vaja {
54076582671SRajan Vaja 	struct device *dev = &pdev->dev;
54176582671SRajan Vaja 	struct device_node *np;
54276582671SRajan Vaja 	int ret;
54376582671SRajan Vaja 
54476582671SRajan Vaja 	np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
54576582671SRajan Vaja 	if (!np)
54676582671SRajan Vaja 		return 0;
54776582671SRajan Vaja 	of_node_put(np);
54876582671SRajan Vaja 
54976582671SRajan Vaja 	ret = get_set_conduit_method(dev->of_node);
55076582671SRajan Vaja 	if (ret)
55176582671SRajan Vaja 		return ret;
55276582671SRajan Vaja 
55376582671SRajan Vaja 	/* Check PM API version number */
55476582671SRajan Vaja 	zynqmp_pm_get_api_version(&pm_api_version);
55576582671SRajan Vaja 	if (pm_api_version < ZYNQMP_PM_VERSION) {
55676582671SRajan Vaja 		panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",
55776582671SRajan Vaja 		      __func__,
55876582671SRajan Vaja 		      ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR,
55976582671SRajan Vaja 		      pm_api_version >> 16, pm_api_version & 0xFFFF);
56076582671SRajan Vaja 	}
56176582671SRajan Vaja 
56276582671SRajan Vaja 	pr_info("%s Platform Management API v%d.%d\n", __func__,
56376582671SRajan Vaja 		pm_api_version >> 16, pm_api_version & 0xFFFF);
56476582671SRajan Vaja 
56576582671SRajan Vaja 	/* Check trustzone version number */
56676582671SRajan Vaja 	ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);
56776582671SRajan Vaja 	if (ret)
56876582671SRajan Vaja 		panic("Legacy trustzone found without version support\n");
56976582671SRajan Vaja 
57076582671SRajan Vaja 	if (pm_tz_version < ZYNQMP_TZ_VERSION)
57176582671SRajan Vaja 		panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",
57276582671SRajan Vaja 		      __func__,
57376582671SRajan Vaja 		      ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR,
57476582671SRajan Vaja 		      pm_tz_version >> 16, pm_tz_version & 0xFFFF);
57576582671SRajan Vaja 
57676582671SRajan Vaja 	pr_info("%s Trustzone version v%d.%d\n", __func__,
57776582671SRajan Vaja 		pm_tz_version >> 16, pm_tz_version & 0xFFFF);
57876582671SRajan Vaja 
579b3217252SRajan Vaja 	zynqmp_pm_api_debugfs_init();
580b3217252SRajan Vaja 
58176582671SRajan Vaja 	return of_platform_populate(dev->of_node, NULL, NULL, dev);
58276582671SRajan Vaja }
58376582671SRajan Vaja 
58476582671SRajan Vaja static int zynqmp_firmware_remove(struct platform_device *pdev)
58576582671SRajan Vaja {
586b3217252SRajan Vaja 	zynqmp_pm_api_debugfs_exit();
587b3217252SRajan Vaja 
58876582671SRajan Vaja 	return 0;
58976582671SRajan Vaja }
59076582671SRajan Vaja 
59176582671SRajan Vaja static const struct of_device_id zynqmp_firmware_of_match[] = {
59276582671SRajan Vaja 	{.compatible = "xlnx,zynqmp-firmware"},
59376582671SRajan Vaja 	{},
59476582671SRajan Vaja };
59576582671SRajan Vaja MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);
59676582671SRajan Vaja 
59776582671SRajan Vaja static struct platform_driver zynqmp_firmware_driver = {
59876582671SRajan Vaja 	.driver = {
59976582671SRajan Vaja 		.name = "zynqmp_firmware",
60076582671SRajan Vaja 		.of_match_table = zynqmp_firmware_of_match,
60176582671SRajan Vaja 	},
60276582671SRajan Vaja 	.probe = zynqmp_firmware_probe,
60376582671SRajan Vaja 	.remove = zynqmp_firmware_remove,
60476582671SRajan Vaja };
60576582671SRajan Vaja module_platform_driver(zynqmp_firmware_driver);
606