brintos

brintos / linux-shallow public Read only

0
0
Text · 52.3 KiB · add8acf Raw
1989 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Xilinx Zynq MPSoC Firmware layer4 *5 *  Copyright (C) 2014-2022 Xilinx, Inc.6 *  Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.7 *8 *  Michal Simek <michal.simek@amd.com>9 *  Davorin Mista <davorin.mista@aggios.com>10 *  Jolly Shah <jollys@xilinx.com>11 *  Rajan Vaja <rajanv@xilinx.com>12 */13 14#include <linux/arm-smccc.h>15#include <linux/compiler.h>16#include <linux/device.h>17#include <linux/init.h>18#include <linux/mfd/core.h>19#include <linux/module.h>20#include <linux/of.h>21#include <linux/of_platform.h>22#include <linux/platform_device.h>23#include <linux/slab.h>24#include <linux/uaccess.h>25#include <linux/hashtable.h>26 27#include <linux/firmware/xlnx-zynqmp.h>28#include <linux/firmware/xlnx-event-manager.h>29#include "zynqmp-debug.h"30 31/* Max HashMap Order for PM API feature check (1<<7 = 128) */32#define PM_API_FEATURE_CHECK_MAX_ORDER  733 34/* CRL registers and bitfields */35#define CRL_APB_BASE			0xFF5E0000U36/* BOOT_PIN_CTRL- Used to control the mode pins after boot */37#define CRL_APB_BOOT_PIN_CTRL		(CRL_APB_BASE + (0x250U))38/* BOOT_PIN_CTRL_MASK- out_val[11:8], out_en[3:0] */39#define CRL_APB_BOOTPIN_CTRL_MASK	0xF0FU40 41/* IOCTL/QUERY feature payload size */42#define FEATURE_PAYLOAD_SIZE		243 44static bool feature_check_enabled;45static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);46static u32 ioctl_features[FEATURE_PAYLOAD_SIZE];47static u32 query_features[FEATURE_PAYLOAD_SIZE];48 49static struct platform_device *em_dev;50 51/**52 * struct zynqmp_devinfo - Structure for Zynqmp device instance53 * @dev:		Device Pointer54 * @feature_conf_id:	Feature conf id55 */56struct zynqmp_devinfo {57	struct device *dev;58	u32 feature_conf_id;59};60 61/**62 * struct pm_api_feature_data - PM API Feature data63 * @pm_api_id:		PM API Id, used as key to index into hashmap64 * @feature_status:	status of PM API feature: valid, invalid65 * @hentry:		hlist_node that hooks this entry into hashtable66 */67struct pm_api_feature_data {68	u32 pm_api_id;69	int feature_status;70	struct hlist_node hentry;71};72 73static const struct mfd_cell firmware_devs[] = {74	{75		.name = "zynqmp_power_controller",76	},77};78 79/**80 * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes81 * @ret_status:		PMUFW return code82 *83 * Return: corresponding Linux error code84 */85static int zynqmp_pm_ret_code(u32 ret_status)86{87	switch (ret_status) {88	case XST_PM_SUCCESS:89	case XST_PM_DOUBLE_REQ:90		return 0;91	case XST_PM_NO_FEATURE:92		return -ENOTSUPP;93	case XST_PM_INVALID_VERSION:94		return -EOPNOTSUPP;95	case XST_PM_NO_ACCESS:96		return -EACCES;97	case XST_PM_ABORT_SUSPEND:98		return -ECANCELED;99	case XST_PM_MULT_USER:100		return -EUSERS;101	case XST_PM_INTERNAL:102	case XST_PM_CONFLICT:103	case XST_PM_INVALID_NODE:104	case XST_PM_INVALID_CRC:105	default:106		return -EINVAL;107	}108}109 110static noinline int do_fw_call_fail(u32 *ret_payload, u32 num_args, ...)111{112	return -ENODEV;113}114 115/*116 * PM function call wrapper117 * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration118 */119static int (*do_fw_call)(u32 *ret_payload, u32, ...) = do_fw_call_fail;120 121/**122 * do_fw_call_smc() - Call system-level platform management layer (SMC)123 * @num_args:		Number of variable arguments should be <= 8124 * @ret_payload:	Returned value array125 *126 * Invoke platform management function via SMC call (no hypervisor present).127 *128 * Return: Returns status, either success or error+reason129 */130static noinline int do_fw_call_smc(u32 *ret_payload, u32 num_args, ...)131{132	struct arm_smccc_res res;133	u64 args[8] = {0};134	va_list arg_list;135	u8 i;136 137	if (num_args > 8)138		return -EINVAL;139 140	va_start(arg_list, num_args);141 142	for (i = 0; i < num_args; i++)143		args[i] = va_arg(arg_list, u64);144 145	va_end(arg_list);146 147	arm_smccc_smc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);148 149	if (ret_payload) {150		ret_payload[0] = lower_32_bits(res.a0);151		ret_payload[1] = upper_32_bits(res.a0);152		ret_payload[2] = lower_32_bits(res.a1);153		ret_payload[3] = upper_32_bits(res.a1);154	}155 156	return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);157}158 159/**160 * do_fw_call_hvc() - Call system-level platform management layer (HVC)161 * @num_args:		Number of variable arguments should be <= 8162 * @ret_payload:	Returned value array163 *164 * Invoke platform management function via HVC165 * HVC-based for communication through hypervisor166 * (no direct communication with ATF).167 *168 * Return: Returns status, either success or error+reason169 */170static noinline int do_fw_call_hvc(u32 *ret_payload, u32 num_args, ...)171{172	struct arm_smccc_res res;173	u64 args[8] = {0};174	va_list arg_list;175	u8 i;176 177	if (num_args > 8)178		return -EINVAL;179 180	va_start(arg_list, num_args);181 182	for (i = 0; i < num_args; i++)183		args[i] = va_arg(arg_list, u64);184 185	va_end(arg_list);186 187	arm_smccc_hvc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);188 189	if (ret_payload) {190		ret_payload[0] = lower_32_bits(res.a0);191		ret_payload[1] = upper_32_bits(res.a0);192		ret_payload[2] = lower_32_bits(res.a1);193		ret_payload[3] = upper_32_bits(res.a1);194	}195 196	return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);197}198 199static int __do_feature_check_call(const u32 api_id, u32 *ret_payload)200{201	int ret;202	u64 smc_arg[2];203	u32 module_id;204	u32 feature_check_api_id;205 206	module_id = FIELD_GET(MODULE_ID_MASK, api_id);207 208	/*209	 * Feature check of APIs belonging to PM, XSEM, and TF-A are handled by calling210	 * PM_FEATURE_CHECK API. For other modules, call PM_API_FEATURES API.211	 */212	if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID || module_id == TF_A_MODULE_ID)213		feature_check_api_id = PM_FEATURE_CHECK;214	else215		feature_check_api_id = PM_API_FEATURES;216 217	/*218	 * Feature check of TF-A APIs is done in the TF-A layer and it expects for219	 * MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID.220	 */221	if (module_id == TF_A_MODULE_ID)222		module_id = PM_MODULE_ID;223 224	smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id;225	smc_arg[1] = (api_id & API_ID_MASK);226 227	ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]);228	if (ret)229		ret = -EOPNOTSUPP;230	else231		ret = ret_payload[1];232 233	return ret;234}235 236static int do_feature_check_call(const u32 api_id)237{238	int ret;239	u32 ret_payload[PAYLOAD_ARG_CNT];240	struct pm_api_feature_data *feature_data;241 242	/* Check for existing entry in hash table for given api */243	hash_for_each_possible(pm_api_features_map, feature_data, hentry,244			       api_id) {245		if (feature_data->pm_api_id == api_id)246			return feature_data->feature_status;247	}248 249	/* Add new entry if not present */250	feature_data = kmalloc(sizeof(*feature_data), GFP_ATOMIC);251	if (!feature_data)252		return -ENOMEM;253 254	feature_data->pm_api_id = api_id;255	ret = __do_feature_check_call(api_id, ret_payload);256 257	feature_data->feature_status = ret;258	hash_add(pm_api_features_map, &feature_data->hentry, api_id);259 260	if (api_id == PM_IOCTL)261		/* Store supported IOCTL IDs mask */262		memcpy(ioctl_features, &ret_payload[2], FEATURE_PAYLOAD_SIZE * 4);263	else if (api_id == PM_QUERY_DATA)264		/* Store supported QUERY IDs mask */265		memcpy(query_features, &ret_payload[2], FEATURE_PAYLOAD_SIZE * 4);266 267	return ret;268}269 270/**271 * zynqmp_pm_feature() - Check whether given feature is supported or not and272 *			 store supported IOCTL/QUERY ID mask273 * @api_id:		API ID to check274 *275 * Return: Returns status, either success or error+reason276 */277int zynqmp_pm_feature(const u32 api_id)278{279	int ret;280 281	if (!feature_check_enabled)282		return 0;283 284	ret = do_feature_check_call(api_id);285 286	return ret;287}288EXPORT_SYMBOL_GPL(zynqmp_pm_feature);289 290/**291 * zynqmp_pm_is_function_supported() - Check whether given IOCTL/QUERY function292 *				       is supported or not293 * @api_id:		PM_IOCTL or PM_QUERY_DATA294 * @id:			IOCTL or QUERY function IDs295 *296 * Return: Returns status, either success or error+reason297 */298int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)299{300	int ret;301	u32 *bit_mask;302 303	/* Input arguments validation */304	if (id >= 64 || (api_id != PM_IOCTL && api_id != PM_QUERY_DATA))305		return -EINVAL;306 307	/* Check feature check API version */308	ret = do_feature_check_call(PM_FEATURE_CHECK);309	if (ret < 0)310		return ret;311 312	/* Check if feature check version 2 is supported or not */313	if ((ret & FIRMWARE_VERSION_MASK) == PM_API_VERSION_2) {314		/*315		 * Call feature check for IOCTL/QUERY API to get IOCTL ID or316		 * QUERY ID feature status.317		 */318		ret = do_feature_check_call(api_id);319		if (ret < 0)320			return ret;321 322		bit_mask = (api_id == PM_IOCTL) ? ioctl_features : query_features;323 324		if ((bit_mask[(id / 32)] & BIT((id % 32))) == 0U)325			return -EOPNOTSUPP;326	} else {327		return -ENODATA;328	}329 330	return 0;331}332EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported);333 334/**335 * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer336 *			   caller function depending on the configuration337 * @pm_api_id:		Requested PM-API call338 * @ret_payload:	Returned value array339 * @num_args:		Number of arguments to requested PM-API call340 *341 * Invoke platform management function for SMC or HVC call, depending on342 * configuration.343 * Following SMC Calling Convention (SMCCC) for SMC64:344 * Pm Function Identifier,345 * PM_SIP_SVC + PM_API_ID =346 *	((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)347 *	((SMC_64) << FUNCID_CC_SHIFT)348 *	((SIP_START) << FUNCID_OEN_SHIFT)349 *	((PM_API_ID) & FUNCID_NUM_MASK))350 *351 * PM_SIP_SVC	- Registered ZynqMP SIP Service Call.352 * PM_API_ID	- Platform Management API ID.353 *354 * Return: Returns status, either success or error+reason355 */356int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...)357{358	/*359	 * Added SIP service call Function Identifier360	 * Make sure to stay in x0 register361	 */362	u64 smc_arg[8];363	int ret, i;364	va_list arg_list;365	u32 args[14] = {0};366 367	if (num_args > 14)368		return -EINVAL;369 370	va_start(arg_list, num_args);371 372	/* Check if feature is supported or not */373	ret = zynqmp_pm_feature(pm_api_id);374	if (ret < 0)375		return ret;376 377	for (i = 0; i < num_args; i++)378		args[i] = va_arg(arg_list, u32);379 380	va_end(arg_list);381 382	smc_arg[0] = PM_SIP_SVC | pm_api_id;383	for (i = 0; i < 7; i++)384		smc_arg[i + 1] = ((u64)args[(i * 2) + 1] << 32) | args[i * 2];385 386	return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3],387			  smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]);388}389 390static u32 pm_api_version;391static u32 pm_tz_version;392static u32 pm_family_code;393static u32 pm_sub_family_code;394 395int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset)396{397	int ret;398 399	ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, NULL, 2, sgi_num, reset);400	if (ret != -EOPNOTSUPP && !ret)401		return ret;402 403	/* try old implementation as fallback strategy if above fails */404	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, IOCTL_REGISTER_SGI, sgi_num, reset);405}406 407/**408 * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware409 * @version:	Returned version value410 *411 * Return: Returns status, either success or error+reason412 */413int zynqmp_pm_get_api_version(u32 *version)414{415	u32 ret_payload[PAYLOAD_ARG_CNT];416	int ret;417 418	if (!version)419		return -EINVAL;420 421	/* Check is PM API version already verified */422	if (pm_api_version > 0) {423		*version = pm_api_version;424		return 0;425	}426	ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, ret_payload, 0);427	*version = ret_payload[1];428 429	return ret;430}431EXPORT_SYMBOL_GPL(zynqmp_pm_get_api_version);432 433/**434 * zynqmp_pm_get_chipid - Get silicon ID registers435 * @idcode:     IDCODE register436 * @version:    version register437 *438 * Return:      Returns the status of the operation and the idcode and version439 *              registers in @idcode and @version.440 */441int zynqmp_pm_get_chipid(u32 *idcode, u32 *version)442{443	u32 ret_payload[PAYLOAD_ARG_CNT];444	int ret;445 446	if (!idcode || !version)447		return -EINVAL;448 449	ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0);450	*idcode = ret_payload[1];451	*version = ret_payload[2];452 453	return ret;454}455EXPORT_SYMBOL_GPL(zynqmp_pm_get_chipid);456 457/**458 * zynqmp_pm_get_family_info() - Get family info of platform459 * @family:	Returned family code value460 * @subfamily:	Returned sub-family code value461 *462 * Return: Returns status, either success or error+reason463 */464int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)465{466	u32 ret_payload[PAYLOAD_ARG_CNT];467	u32 idcode;468	int ret;469 470	/* Check is family or sub-family code already received */471	if (pm_family_code && pm_sub_family_code) {472		*family = pm_family_code;473		*subfamily = pm_sub_family_code;474		return 0;475	}476 477	ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0);478	if (ret < 0)479		return ret;480 481	idcode = ret_payload[1];482	pm_family_code = FIELD_GET(FAMILY_CODE_MASK, idcode);483	pm_sub_family_code = FIELD_GET(SUB_FAMILY_CODE_MASK, idcode);484	*family = pm_family_code;485	*subfamily = pm_sub_family_code;486 487	return 0;488}489EXPORT_SYMBOL_GPL(zynqmp_pm_get_family_info);490 491/**492 * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version493 * @version:	Returned version value494 *495 * Return: Returns status, either success or error+reason496 */497static int zynqmp_pm_get_trustzone_version(u32 *version)498{499	u32 ret_payload[PAYLOAD_ARG_CNT];500	int ret;501 502	if (!version)503		return -EINVAL;504 505	/* Check is PM trustzone version already verified */506	if (pm_tz_version > 0) {507		*version = pm_tz_version;508		return 0;509	}510	ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, ret_payload, 0);511	*version = ret_payload[1];512 513	return ret;514}515 516/**517 * get_set_conduit_method() - Choose SMC or HVC based communication518 * @np:		Pointer to the device_node structure519 *520 * Use SMC or HVC-based functions to communicate with EL2/EL3.521 *522 * Return: Returns 0 on success or error code523 */524static int get_set_conduit_method(struct device_node *np)525{526	const char *method;527 528	if (of_property_read_string(np, "method", &method)) {529		pr_warn("%s missing \"method\" property\n", __func__);530		return -ENXIO;531	}532 533	if (!strcmp("hvc", method)) {534		do_fw_call = do_fw_call_hvc;535	} else if (!strcmp("smc", method)) {536		do_fw_call = do_fw_call_smc;537	} else {538		pr_warn("%s Invalid \"method\" property: %s\n",539			__func__, method);540		return -EINVAL;541	}542 543	return 0;544}545 546/**547 * zynqmp_pm_query_data() - Get query data from firmware548 * @qdata:	Variable to the zynqmp_pm_query_data structure549 * @out:	Returned output value550 *551 * Return: Returns status, either success or error+reason552 */553int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)554{555	int ret;556 557	ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, qdata.arg1, qdata.arg2,558				  qdata.arg3);559 560	/*561	 * For clock name query, all bytes in SMC response are clock name562	 * characters and return code is always success. For invalid clocks,563	 * clock name bytes would be zeros.564	 */565	return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;566}567EXPORT_SYMBOL_GPL(zynqmp_pm_query_data);568 569/**570 * zynqmp_pm_clock_enable() - Enable the clock for given id571 * @clock_id:	ID of the clock to be enabled572 *573 * This function is used by master to enable the clock574 * including peripherals and PLL clocks.575 *576 * Return: Returns status, either success or error+reason577 */578int zynqmp_pm_clock_enable(u32 clock_id)579{580	return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, NULL, 1, clock_id);581}582EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable);583 584/**585 * zynqmp_pm_clock_disable() - Disable the clock for given id586 * @clock_id:	ID of the clock to be disable587 *588 * This function is used by master to disable the clock589 * including peripherals and PLL clocks.590 *591 * Return: Returns status, either success or error+reason592 */593int zynqmp_pm_clock_disable(u32 clock_id)594{595	return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, NULL, 1, clock_id);596}597EXPORT_SYMBOL_GPL(zynqmp_pm_clock_disable);598 599/**600 * zynqmp_pm_clock_getstate() - Get the clock state for given id601 * @clock_id:	ID of the clock to be queried602 * @state:	1/0 (Enabled/Disabled)603 *604 * This function is used by master to get the state of clock605 * including peripherals and PLL clocks.606 *607 * Return: Returns status, either success or error+reason608 */609int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)610{611	u32 ret_payload[PAYLOAD_ARG_CNT];612	int ret;613 614	ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, ret_payload, 1, clock_id);615	*state = ret_payload[1];616 617	return ret;618}619EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getstate);620 621/**622 * zynqmp_pm_clock_setdivider() - Set the clock divider for given id623 * @clock_id:	ID of the clock624 * @divider:	divider value625 *626 * This function is used by master to set divider for any clock627 * to achieve desired rate.628 *629 * Return: Returns status, either success or error+reason630 */631int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)632{633	return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, NULL, 2, clock_id, divider);634}635EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setdivider);636 637/**638 * zynqmp_pm_clock_getdivider() - Get the clock divider for given id639 * @clock_id:	ID of the clock640 * @divider:	divider value641 *642 * This function is used by master to get divider values643 * for any clock.644 *645 * Return: Returns status, either success or error+reason646 */647int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)648{649	u32 ret_payload[PAYLOAD_ARG_CNT];650	int ret;651 652	ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, ret_payload, 1, clock_id);653	*divider = ret_payload[1];654 655	return ret;656}657EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getdivider);658 659/**660 * zynqmp_pm_clock_setparent() - Set the clock parent for given id661 * @clock_id:	ID of the clock662 * @parent_id:	parent id663 *664 * This function is used by master to set parent for any clock.665 *666 * Return: Returns status, either success or error+reason667 */668int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)669{670	return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, NULL, 2, clock_id, parent_id);671}672EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setparent);673 674/**675 * zynqmp_pm_clock_getparent() - Get the clock parent for given id676 * @clock_id:	ID of the clock677 * @parent_id:	parent id678 *679 * This function is used by master to get parent index680 * for any clock.681 *682 * Return: Returns status, either success or error+reason683 */684int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)685{686	u32 ret_payload[PAYLOAD_ARG_CNT];687	int ret;688 689	ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, ret_payload, 1, clock_id);690	*parent_id = ret_payload[1];691 692	return ret;693}694EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getparent);695 696/**697 * zynqmp_pm_set_pll_frac_mode() - PM API for set PLL mode698 *699 * @clk_id:	PLL clock ID700 * @mode:	PLL mode (PLL_MODE_FRAC/PLL_MODE_INT)701 *702 * This function sets PLL mode703 *704 * Return: Returns status, either success or error+reason705 */706int zynqmp_pm_set_pll_frac_mode(u32 clk_id, u32 mode)707{708	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_MODE, clk_id, mode);709}710EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode);711 712/**713 * zynqmp_pm_get_pll_frac_mode() - PM API for get PLL mode714 *715 * @clk_id:	PLL clock ID716 * @mode:	PLL mode717 *718 * This function return current PLL mode719 *720 * Return: Returns status, either success or error+reason721 */722int zynqmp_pm_get_pll_frac_mode(u32 clk_id, u32 *mode)723{724	return zynqmp_pm_invoke_fn(PM_IOCTL, mode, 3, 0, IOCTL_GET_PLL_FRAC_MODE, clk_id);725}726EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode);727 728/**729 * zynqmp_pm_set_pll_frac_data() - PM API for setting pll fraction data730 *731 * @clk_id:	PLL clock ID732 * @data:	fraction data733 *734 * This function sets fraction data.735 * It is valid for fraction mode only.736 *737 * Return: Returns status, either success or error+reason738 */739int zynqmp_pm_set_pll_frac_data(u32 clk_id, u32 data)740{741	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_DATA, clk_id, data);742}743EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data);744 745/**746 * zynqmp_pm_get_pll_frac_data() - PM API for getting pll fraction data747 *748 * @clk_id:	PLL clock ID749 * @data:	fraction data750 *751 * This function returns fraction data value.752 *753 * Return: Returns status, either success or error+reason754 */755int zynqmp_pm_get_pll_frac_data(u32 clk_id, u32 *data)756{757	return zynqmp_pm_invoke_fn(PM_IOCTL, data, 3, 0, IOCTL_GET_PLL_FRAC_DATA, clk_id);758}759EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data);760 761/**762 * zynqmp_pm_set_sd_tapdelay() -  Set tap delay for the SD device763 *764 * @node_id:	Node ID of the device765 * @type:	Type of tap delay to set (input/output)766 * @value:	Value to set fot the tap delay767 *768 * This function sets input/output tap delay for the SD device.769 *770 * Return:	Returns status, either success or error+reason771 */772int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)773{774	u32 reg = (type == PM_TAPDELAY_INPUT) ? SD_ITAPDLY : SD_OTAPDLYSEL;775	u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16);776 777	if (value) {778		return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node_id, IOCTL_SET_SD_TAPDELAY, type,779					   value);780	}781 782	/*783	 * Work around completely misdesigned firmware API on Xilinx ZynqMP.784	 * The IOCTL_SET_SD_TAPDELAY firmware call allows the caller to only785	 * ever set IOU_SLCR SD_ITAPDLY Register SD0_ITAPDLYENA/SD1_ITAPDLYENA786	 * bits, but there is no matching call to clear those bits. If those787	 * bits are not cleared, SDMMC tuning may fail.788	 *789	 * Luckily, there are PM_MMIO_READ/PM_MMIO_WRITE calls which seem to790	 * allow complete unrestricted access to all address space, including791	 * IOU_SLCR SD_ITAPDLY Register and all the other registers, access792	 * to which was supposed to be protected by the current firmware API.793	 *794	 * Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter795	 * part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits.796	 */797	return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 2, reg, mask);798}799EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);800 801/**802 * zynqmp_pm_sd_dll_reset() - Reset DLL logic803 *804 * @node_id:	Node ID of the device805 * @type:	Reset type806 *807 * This function resets DLL logic for the SD device.808 *809 * Return:	Returns status, either success or error+reason810 */811int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type)812{813	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SD_DLL_RESET, type);814}815EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);816 817/**818 * zynqmp_pm_ospi_mux_select() - OSPI Mux selection819 *820 * @dev_id:	Device Id of the OSPI device.821 * @select:	OSPI Mux select value.822 *823 * This function select the OSPI Mux.824 *825 * Return:	Returns status, either success or error+reason826 */827int zynqmp_pm_ospi_mux_select(u32 dev_id, u32 select)828{829	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, dev_id, IOCTL_OSPI_MUX_SELECT, select);830}831EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select);832 833/**834 * zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs)835 * @index:	GGS register index836 * @value:	Register value to be written837 *838 * This function writes value to GGS register.839 *840 * Return:      Returns status, either success or error+reason841 */842int zynqmp_pm_write_ggs(u32 index, u32 value)843{844	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_GGS, index, value);845}846EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);847 848/**849 * zynqmp_pm_read_ggs() - PM API for reading global general storage (ggs)850 * @index:	GGS register index851 * @value:	Register value to be written852 *853 * This function returns GGS register value.854 *855 * Return:	Returns status, either success or error+reason856 */857int zynqmp_pm_read_ggs(u32 index, u32 *value)858{859	return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_GGS, index);860}861EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);862 863/**864 * zynqmp_pm_write_pggs() - PM API for writing persistent global general865 *			     storage (pggs)866 * @index:	PGGS register index867 * @value:	Register value to be written868 *869 * This function writes value to PGGS register.870 *871 * Return:	Returns status, either success or error+reason872 */873int zynqmp_pm_write_pggs(u32 index, u32 value)874{875	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_PGGS, index, value);876}877EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);878 879/**880 * zynqmp_pm_read_pggs() - PM API for reading persistent global general881 *			     storage (pggs)882 * @index:	PGGS register index883 * @value:	Register value to be written884 *885 * This function returns PGGS register value.886 *887 * Return:	Returns status, either success or error+reason888 */889int zynqmp_pm_read_pggs(u32 index, u32 *value)890{891	return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_PGGS, index);892}893EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);894 895int zynqmp_pm_set_tapdelay_bypass(u32 index, u32 value)896{897	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_TAPDELAY_BYPASS, index, value);898}899EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass);900 901/**902 * zynqmp_pm_set_boot_health_status() - PM API for setting healthy boot status903 * @value:	Status value to be written904 *905 * This function sets healthy bit value to indicate boot health status906 * to firmware.907 *908 * Return:	Returns status, either success or error+reason909 */910int zynqmp_pm_set_boot_health_status(u32 value)911{912	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, 0, IOCTL_SET_BOOT_HEALTH_STATUS, value);913}914 915/**916 * zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release)917 * @reset:		Reset to be configured918 * @assert_flag:	Flag stating should reset be asserted (1) or919 *			released (0)920 *921 * Return: Returns status, either success or error+reason922 */923int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,924			   const enum zynqmp_pm_reset_action assert_flag)925{926	return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, NULL, 2, reset, assert_flag);927}928EXPORT_SYMBOL_GPL(zynqmp_pm_reset_assert);929 930/**931 * zynqmp_pm_reset_get_status - Get status of the reset932 * @reset:      Reset whose status should be returned933 * @status:     Returned status934 *935 * Return: Returns status, either success or error+reason936 */937int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status)938{939	u32 ret_payload[PAYLOAD_ARG_CNT];940	int ret;941 942	if (!status)943		return -EINVAL;944 945	ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, ret_payload, 1, reset);946	*status = ret_payload[1];947 948	return ret;949}950EXPORT_SYMBOL_GPL(zynqmp_pm_reset_get_status);951 952/**953 * zynqmp_pm_fpga_load - Perform the fpga load954 * @address:	Address to write to955 * @size:	pl bitstream size956 * @flags:	Bitstream type957 *	-XILINX_ZYNQMP_PM_FPGA_FULL:  FPGA full reconfiguration958 *	-XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration959 *960 * This function provides access to pmufw. To transfer961 * the required bitstream into PL.962 *963 * Return: Returns status, either success or error+reason964 */965int zynqmp_pm_fpga_load(const u64 address, const u32 size, const u32 flags)966{967	u32 ret_payload[PAYLOAD_ARG_CNT];968	int ret;969 970	ret = zynqmp_pm_invoke_fn(PM_FPGA_LOAD, ret_payload, 4, lower_32_bits(address),971				  upper_32_bits(address), size, flags);972	if (ret_payload[0])973		return -ret_payload[0];974 975	return ret;976}977EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_load);978 979/**980 * zynqmp_pm_fpga_get_status - Read value from PCAP status register981 * @value: Value to read982 *983 * This function provides access to the pmufw to get the PCAP984 * status985 *986 * Return: Returns status, either success or error+reason987 */988int zynqmp_pm_fpga_get_status(u32 *value)989{990	u32 ret_payload[PAYLOAD_ARG_CNT];991	int ret;992 993	if (!value)994		return -EINVAL;995 996	ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, ret_payload, 0);997	*value = ret_payload[1];998 999	return ret;1000}1001EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_status);1002 1003/**1004 * zynqmp_pm_fpga_get_config_status - Get the FPGA configuration status.1005 * @value: Buffer to store FPGA configuration status.1006 *1007 * This function provides access to the pmufw to get the FPGA configuration1008 * status1009 *1010 * Return: 0 on success, a negative value on error1011 */1012int zynqmp_pm_fpga_get_config_status(u32 *value)1013{1014	u32 ret_payload[PAYLOAD_ARG_CNT];1015	u32 buf, lower_addr, upper_addr;1016	int ret;1017 1018	if (!value)1019		return -EINVAL;1020 1021	lower_addr = lower_32_bits((u64)&buf);1022	upper_addr = upper_32_bits((u64)&buf);1023 1024	ret = zynqmp_pm_invoke_fn(PM_FPGA_READ, ret_payload, 4,1025				  XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, lower_addr, upper_addr,1026				  XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG);1027 1028	*value = ret_payload[1];1029 1030	return ret;1031}1032EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_config_status);1033 1034/**1035 * zynqmp_pm_pinctrl_request - Request Pin from firmware1036 * @pin: Pin number to request1037 *1038 * This function requests pin from firmware.1039 *1040 * Return: Returns status, either success or error+reason.1041 */1042int zynqmp_pm_pinctrl_request(const u32 pin)1043{1044	return zynqmp_pm_invoke_fn(PM_PINCTRL_REQUEST, NULL, 1, pin);1045}1046EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_request);1047 1048/**1049 * zynqmp_pm_pinctrl_release - Inform firmware that Pin control is released1050 * @pin: Pin number to release1051 *1052 * This function release pin from firmware.1053 *1054 * Return: Returns status, either success or error+reason.1055 */1056int zynqmp_pm_pinctrl_release(const u32 pin)1057{1058	return zynqmp_pm_invoke_fn(PM_PINCTRL_RELEASE, NULL, 1, pin);1059}1060EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_release);1061 1062/**1063 * zynqmp_pm_pinctrl_set_function - Set requested function for the pin1064 * @pin: Pin number1065 * @id: Function ID to set1066 *1067 * This function sets requested function for the given pin.1068 *1069 * Return: Returns status, either success or error+reason.1070 */1071int zynqmp_pm_pinctrl_set_function(const u32 pin, const u32 id)1072{1073	return zynqmp_pm_invoke_fn(PM_PINCTRL_SET_FUNCTION, NULL, 2, pin, id);1074}1075EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_function);1076 1077/**1078 * zynqmp_pm_pinctrl_get_config - Get configuration parameter for the pin1079 * @pin: Pin number1080 * @param: Parameter to get1081 * @value: Buffer to store parameter value1082 *1083 * This function gets requested configuration parameter for the given pin.1084 *1085 * Return: Returns status, either success or error+reason.1086 */1087int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param,1088				 u32 *value)1089{1090	u32 ret_payload[PAYLOAD_ARG_CNT];1091	int ret;1092 1093	if (!value)1094		return -EINVAL;1095 1096	ret = zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_GET, ret_payload, 2, pin, param);1097	*value = ret_payload[1];1098 1099	return ret;1100}1101EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_get_config);1102 1103/**1104 * zynqmp_pm_pinctrl_set_config - Set configuration parameter for the pin1105 * @pin: Pin number1106 * @param: Parameter to set1107 * @value: Parameter value to set1108 *1109 * This function sets requested configuration parameter for the given pin.1110 *1111 * Return: Returns status, either success or error+reason.1112 */1113int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param,1114				 u32 value)1115{1116	int ret;1117 1118	if (pm_family_code == ZYNQMP_FAMILY_CODE &&1119	    param == PM_PINCTRL_CONFIG_TRI_STATE) {1120		ret = zynqmp_pm_feature(PM_PINCTRL_CONFIG_PARAM_SET);1121		if (ret < PM_PINCTRL_PARAM_SET_VERSION)1122			return -EOPNOTSUPP;1123	}1124 1125	return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, NULL, 3, pin, param, value);1126}1127EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_config);1128 1129/**1130 * zynqmp_pm_bootmode_read() - PM Config API for read bootpin status1131 * @ps_mode: Returned output value of ps_mode1132 *1133 * This API function is to be used for notify the power management controller1134 * to read bootpin status.1135 *1136 * Return: status, either success or error+reason1137 */1138unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode)1139{1140	unsigned int ret;1141	u32 ret_payload[PAYLOAD_ARG_CNT];1142 1143	ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, ret_payload, 1, CRL_APB_BOOT_PIN_CTRL);1144 1145	*ps_mode = ret_payload[1];1146 1147	return ret;1148}1149EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_read);1150 1151/**1152 * zynqmp_pm_bootmode_write() - PM Config API for Configure bootpin1153 * @ps_mode: Value to be written to the bootpin ctrl register1154 *1155 * This API function is to be used for notify the power management controller1156 * to configure bootpin.1157 *1158 * Return: Returns status, either success or error+reason1159 */1160int zynqmp_pm_bootmode_write(u32 ps_mode)1161{1162	return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 3, CRL_APB_BOOT_PIN_CTRL,1163				   CRL_APB_BOOTPIN_CTRL_MASK, ps_mode);1164}1165EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write);1166 1167/**1168 * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller1169 *			       master has initialized its own power management1170 *1171 * Return: Returns status, either success or error+reason1172 *1173 * This API function is to be used for notify the power management controller1174 * about the completed power management initialization.1175 */1176int zynqmp_pm_init_finalize(void)1177{1178	return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, NULL, 0);1179}1180EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize);1181 1182/**1183 * zynqmp_pm_set_suspend_mode()	- Set system suspend mode1184 * @mode:	Mode to set for system suspend1185 *1186 * This API function is used to set mode of system suspend.1187 *1188 * Return: Returns status, either success or error+reason1189 */1190int zynqmp_pm_set_suspend_mode(u32 mode)1191{1192	return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, NULL, 1, mode);1193}1194EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode);1195 1196/**1197 * zynqmp_pm_request_node() - Request a node with specific capabilities1198 * @node:		Node ID of the slave1199 * @capabilities:	Requested capabilities of the slave1200 * @qos:		Quality of service (not supported)1201 * @ack:		Flag to specify whether acknowledge is requested1202 *1203 * This function is used by master to request particular node from firmware.1204 * Every master must request node before using it.1205 *1206 * Return: Returns status, either success or error+reason1207 */1208int zynqmp_pm_request_node(const u32 node, const u32 capabilities,1209			   const u32 qos, const enum zynqmp_pm_request_ack ack)1210{1211	return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, NULL, 4, node, capabilities, qos, ack);1212}1213EXPORT_SYMBOL_GPL(zynqmp_pm_request_node);1214 1215/**1216 * zynqmp_pm_release_node() - Release a node1217 * @node:	Node ID of the slave1218 *1219 * This function is used by master to inform firmware that master1220 * has released node. Once released, master must not use that node1221 * without re-request.1222 *1223 * Return: Returns status, either success or error+reason1224 */1225int zynqmp_pm_release_node(const u32 node)1226{1227	return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, NULL, 1, node);1228}1229EXPORT_SYMBOL_GPL(zynqmp_pm_release_node);1230 1231/**1232 * zynqmp_pm_get_rpu_mode() - Get RPU mode1233 * @node_id:	Node ID of the device1234 * @rpu_mode:	return by reference value1235 *		either split or lockstep1236 *1237 * Return:	return 0 on success or error+reason.1238 *		if success, then  rpu_mode will be set1239 *		to current rpu mode.1240 */1241int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode)1242{1243	u32 ret_payload[PAYLOAD_ARG_CNT];1244	int ret;1245 1246	ret = zynqmp_pm_invoke_fn(PM_IOCTL, ret_payload, 2, node_id, IOCTL_GET_RPU_OPER_MODE);1247 1248	/* only set rpu_mode if no error */1249	if (ret == XST_PM_SUCCESS)1250		*rpu_mode = ret_payload[0];1251 1252	return ret;1253}1254EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_mode);1255 1256/**1257 * zynqmp_pm_set_rpu_mode() - Set RPU mode1258 * @node_id:	Node ID of the device1259 * @rpu_mode:	Argument 1 to requested IOCTL call. either split or lockstep1260 *1261 *		This function is used to set RPU mode to split or1262 *		lockstep1263 *1264 * Return:	Returns status, either success or error+reason1265 */1266int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode)1267{1268	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SET_RPU_OPER_MODE,1269				   (u32)rpu_mode);1270}1271EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode);1272 1273/**1274 * zynqmp_pm_set_tcm_config - configure TCM1275 * @node_id:	Firmware specific TCM subsystem ID1276 * @tcm_mode:	Argument 1 to requested IOCTL call1277 *              either PM_RPU_TCM_COMB or PM_RPU_TCM_SPLIT1278 *1279 * This function is used to set RPU mode to split or combined1280 *1281 * Return: status: 0 for success, else failure1282 */1283int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode)1284{1285	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_TCM_COMB_CONFIG,1286				   (u32)tcm_mode);1287}1288EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config);1289 1290/**1291 * zynqmp_pm_force_pwrdwn - PM call to request for another PU or subsystem to1292 *             be powered down forcefully1293 * @node:  Node ID of the targeted PU or subsystem1294 * @ack:   Flag to specify whether acknowledge is requested1295 *1296 * Return: status, either success or error+reason1297 */1298int zynqmp_pm_force_pwrdwn(const u32 node,1299			   const enum zynqmp_pm_request_ack ack)1300{1301	return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, NULL, 2, node, ack);1302}1303EXPORT_SYMBOL_GPL(zynqmp_pm_force_pwrdwn);1304 1305/**1306 * zynqmp_pm_request_wake - PM call to wake up selected master or subsystem1307 * @node:  Node ID of the master or subsystem1308 * @set_addr:  Specifies whether the address argument is relevant1309 * @address:   Address from which to resume when woken up1310 * @ack:   Flag to specify whether acknowledge requested1311 *1312 * Return: status, either success or error+reason1313 */1314int zynqmp_pm_request_wake(const u32 node,1315			   const bool set_addr,1316			   const u64 address,1317			   const enum zynqmp_pm_request_ack ack)1318{1319	/* set_addr flag is encoded into 1st bit of address */1320	return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, NULL, 4, node, address | set_addr,1321				   address >> 32, ack);1322}1323EXPORT_SYMBOL_GPL(zynqmp_pm_request_wake);1324 1325/**1326 * zynqmp_pm_set_requirement() - PM call to set requirement for PM slaves1327 * @node:		Node ID of the slave1328 * @capabilities:	Requested capabilities of the slave1329 * @qos:		Quality of service (not supported)1330 * @ack:		Flag to specify whether acknowledge is requested1331 *1332 * This API function is to be used for slaves a PU already has requested1333 * to change its capabilities.1334 *1335 * Return: Returns status, either success or error+reason1336 */1337int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,1338			      const u32 qos,1339			      const enum zynqmp_pm_request_ack ack)1340{1341	return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, NULL, 4, node, capabilities, qos, ack);1342}1343EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);1344 1345/**1346 * zynqmp_pm_load_pdi - Load and process PDI1347 * @src:	Source device where PDI is located1348 * @address:	PDI src address1349 *1350 * This function provides support to load PDI from linux1351 *1352 * Return: Returns status, either success or error+reason1353 */1354int zynqmp_pm_load_pdi(const u32 src, const u64 address)1355{1356	return zynqmp_pm_invoke_fn(PM_LOAD_PDI, NULL, 3, src, lower_32_bits(address),1357				   upper_32_bits(address));1358}1359EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi);1360 1361/**1362 * zynqmp_pm_aes_engine - Access AES hardware to encrypt/decrypt the data using1363 * AES-GCM core.1364 * @address:	Address of the AesParams structure.1365 * @out:	Returned output value1366 *1367 * Return:	Returns status, either success or error code.1368 */1369int zynqmp_pm_aes_engine(const u64 address, u32 *out)1370{1371	u32 ret_payload[PAYLOAD_ARG_CNT];1372	int ret;1373 1374	if (!out)1375		return -EINVAL;1376 1377	ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, ret_payload, 2, upper_32_bits(address),1378				  lower_32_bits(address));1379	*out = ret_payload[1];1380 1381	return ret;1382}1383EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine);1384 1385/**1386 * zynqmp_pm_efuse_access - Provides access to efuse memory.1387 * @address:	Address of the efuse params structure1388 * @out:		Returned output value1389 *1390 * Return:	Returns status, either success or error code.1391 */1392int zynqmp_pm_efuse_access(const u64 address, u32 *out)1393{1394	u32 ret_payload[PAYLOAD_ARG_CNT];1395	int ret;1396 1397	if (!out)1398		return -EINVAL;1399 1400	ret = zynqmp_pm_invoke_fn(PM_EFUSE_ACCESS, ret_payload, 2,1401				  upper_32_bits(address),1402				  lower_32_bits(address));1403	*out = ret_payload[1];1404 1405	return ret;1406}1407EXPORT_SYMBOL_GPL(zynqmp_pm_efuse_access);1408 1409/**1410 * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash1411 * @address:	Address of the data/ Address of output buffer where1412 *		hash should be stored.1413 * @size:	Size of the data.1414 * @flags:1415 *	BIT(0) - for initializing csudma driver and SHA3(Here address1416 *		 and size inputs can be NULL).1417 *	BIT(1) - to call Sha3_Update API which can be called multiple1418 *		 times when data is not contiguous.1419 *	BIT(2) - to get final hash of the whole updated data.1420 *		 Hash will be overwritten at provided address with1421 *		 48 bytes.1422 *1423 * Return:	Returns status, either success or error code.1424 */1425int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags)1426{1427	u32 lower_addr = lower_32_bits(address);1428	u32 upper_addr = upper_32_bits(address);1429 1430	return zynqmp_pm_invoke_fn(PM_SECURE_SHA, NULL, 4, upper_addr, lower_addr, size, flags);1431}1432EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);1433 1434/**1435 * zynqmp_pm_register_notifier() - PM API for register a subsystem1436 *                                to be notified about specific1437 *                                event/error.1438 * @node:	Node ID to which the event is related.1439 * @event:	Event Mask of Error events for which wants to get notified.1440 * @wake:	Wake subsystem upon capturing the event if value 11441 * @enable:	Enable the registration for value 1, disable for value 01442 *1443 * This function is used to register/un-register for particular node-event1444 * combination in firmware.1445 *1446 * Return: Returns status, either success or error+reason1447 */1448 1449int zynqmp_pm_register_notifier(const u32 node, const u32 event,1450				const u32 wake, const u32 enable)1451{1452	return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, NULL, 4, node, event, wake, enable);1453}1454EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier);1455 1456/**1457 * zynqmp_pm_system_shutdown - PM call to request a system shutdown or restart1458 * @type:	Shutdown or restart? 0 for shutdown, 1 for restart1459 * @subtype:	Specifies which system should be restarted or shut down1460 *1461 * Return:	Returns status, either success or error+reason1462 */1463int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)1464{1465	return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, NULL, 2, type, subtype);1466}1467 1468/**1469 * zynqmp_pm_set_feature_config - PM call to request IOCTL for feature config1470 * @id:         The config ID of the feature to be configured1471 * @value:      The config value of the feature to be configured1472 *1473 * Return:      Returns 0 on success or error value on failure.1474 */1475int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value)1476{1477	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_FEATURE_CONFIG, id, value);1478}1479 1480/**1481 * zynqmp_pm_get_feature_config - PM call to get value of configured feature1482 * @id:         The config id of the feature to be queried1483 * @payload:    Returned value array1484 *1485 * Return:      Returns 0 on success or error value on failure.1486 */1487int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,1488				 u32 *payload)1489{1490	return zynqmp_pm_invoke_fn(PM_IOCTL, payload, 3, 0, IOCTL_GET_FEATURE_CONFIG, id);1491}1492 1493/**1494 * zynqmp_pm_set_sd_config - PM call to set value of SD config registers1495 * @node:	SD node ID1496 * @config:	The config type of SD registers1497 * @value:	Value to be set1498 *1499 * Return:	Returns 0 on success or error value on failure.1500 */1501int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value)1502{1503	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_SD_CONFIG, config, value);1504}1505EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_config);1506 1507/**1508 * zynqmp_pm_set_gem_config - PM call to set value of GEM config registers1509 * @node:	GEM node ID1510 * @config:	The config type of GEM registers1511 * @value:	Value to be set1512 *1513 * Return:	Returns 0 on success or error value on failure.1514 */1515int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config,1516			     u32 value)1517{1518	return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_GEM_CONFIG, config, value);1519}1520EXPORT_SYMBOL_GPL(zynqmp_pm_set_gem_config);1521 1522/**1523 * struct zynqmp_pm_shutdown_scope - Struct for shutdown scope1524 * @subtype:	Shutdown subtype1525 * @name:	Matching string for scope argument1526 *1527 * This struct encapsulates mapping between shutdown scope ID and string.1528 */1529struct zynqmp_pm_shutdown_scope {1530	const enum zynqmp_pm_shutdown_subtype subtype;1531	const char *name;1532};1533 1534static struct zynqmp_pm_shutdown_scope shutdown_scopes[] = {1535	[ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM] = {1536		.subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM,1537		.name = "subsystem",1538	},1539	[ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY] = {1540		.subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY,1541		.name = "ps_only",1542	},1543	[ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM] = {1544		.subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM,1545		.name = "system",1546	},1547};1548 1549static struct zynqmp_pm_shutdown_scope *selected_scope =1550		&shutdown_scopes[ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM];1551 1552/**1553 * zynqmp_pm_is_shutdown_scope_valid - Check if shutdown scope string is valid1554 * @scope_string:	Shutdown scope string1555 *1556 * Return:		Return pointer to matching shutdown scope struct from1557 *			array of available options in system if string is valid,1558 *			otherwise returns NULL.1559 */1560static struct zynqmp_pm_shutdown_scope*1561		zynqmp_pm_is_shutdown_scope_valid(const char *scope_string)1562{1563	int count;1564 1565	for (count = 0; count < ARRAY_SIZE(shutdown_scopes); count++)1566		if (sysfs_streq(scope_string, shutdown_scopes[count].name))1567			return &shutdown_scopes[count];1568 1569	return NULL;1570}1571 1572static ssize_t shutdown_scope_show(struct device *device,1573				   struct device_attribute *attr,1574				   char *buf)1575{1576	int i;1577 1578	for (i = 0; i < ARRAY_SIZE(shutdown_scopes); i++) {1579		if (&shutdown_scopes[i] == selected_scope) {1580			strcat(buf, "[");1581			strcat(buf, shutdown_scopes[i].name);1582			strcat(buf, "]");1583		} else {1584			strcat(buf, shutdown_scopes[i].name);1585		}1586		strcat(buf, " ");1587	}1588	strcat(buf, "\n");1589 1590	return strlen(buf);1591}1592 1593static ssize_t shutdown_scope_store(struct device *device,1594				    struct device_attribute *attr,1595				    const char *buf, size_t count)1596{1597	int ret;1598	struct zynqmp_pm_shutdown_scope *scope;1599 1600	scope = zynqmp_pm_is_shutdown_scope_valid(buf);1601	if (!scope)1602		return -EINVAL;1603 1604	ret = zynqmp_pm_system_shutdown(ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY,1605					scope->subtype);1606	if (ret) {1607		pr_err("unable to set shutdown scope %s\n", buf);1608		return ret;1609	}1610 1611	selected_scope = scope;1612 1613	return count;1614}1615 1616static DEVICE_ATTR_RW(shutdown_scope);1617 1618static ssize_t health_status_store(struct device *device,1619				   struct device_attribute *attr,1620				   const char *buf, size_t count)1621{1622	int ret;1623	unsigned int value;1624 1625	ret = kstrtouint(buf, 10, &value);1626	if (ret)1627		return ret;1628 1629	ret = zynqmp_pm_set_boot_health_status(value);1630	if (ret) {1631		dev_err(device, "unable to set healthy bit value to %u\n",1632			value);1633		return ret;1634	}1635 1636	return count;1637}1638 1639static DEVICE_ATTR_WO(health_status);1640 1641static ssize_t ggs_show(struct device *device,1642			struct device_attribute *attr,1643			char *buf,1644			u32 reg)1645{1646	int ret;1647	u32 ret_payload[PAYLOAD_ARG_CNT];1648 1649	ret = zynqmp_pm_read_ggs(reg, ret_payload);1650	if (ret)1651		return ret;1652 1653	return sprintf(buf, "0x%x\n", ret_payload[1]);1654}1655 1656static ssize_t ggs_store(struct device *device,1657			 struct device_attribute *attr,1658			 const char *buf, size_t count,1659			 u32 reg)1660{1661	long value;1662	int ret;1663 1664	if (reg >= GSS_NUM_REGS)1665		return -EINVAL;1666 1667	ret = kstrtol(buf, 16, &value);1668	if (ret) {1669		count = -EFAULT;1670		goto err;1671	}1672 1673	ret = zynqmp_pm_write_ggs(reg, value);1674	if (ret)1675		count = -EFAULT;1676err:1677	return count;1678}1679 1680/* GGS register show functions */1681#define GGS0_SHOW(N)						\1682	ssize_t ggs##N##_show(struct device *device,		\1683			      struct device_attribute *attr,	\1684			      char *buf)			\1685	{							\1686		return ggs_show(device, attr, buf, N);		\1687	}1688 1689static GGS0_SHOW(0);1690static GGS0_SHOW(1);1691static GGS0_SHOW(2);1692static GGS0_SHOW(3);1693 1694/* GGS register store function */1695#define GGS0_STORE(N)						\1696	ssize_t ggs##N##_store(struct device *device,		\1697			       struct device_attribute *attr,	\1698			       const char *buf,			\1699			       size_t count)			\1700	{							\1701		return ggs_store(device, attr, buf, count, N);	\1702	}1703 1704static GGS0_STORE(0);1705static GGS0_STORE(1);1706static GGS0_STORE(2);1707static GGS0_STORE(3);1708 1709static ssize_t pggs_show(struct device *device,1710			 struct device_attribute *attr,1711			 char *buf,1712			 u32 reg)1713{1714	int ret;1715	u32 ret_payload[PAYLOAD_ARG_CNT];1716 1717	ret = zynqmp_pm_read_pggs(reg, ret_payload);1718	if (ret)1719		return ret;1720 1721	return sprintf(buf, "0x%x\n", ret_payload[1]);1722}1723 1724static ssize_t pggs_store(struct device *device,1725			  struct device_attribute *attr,1726			  const char *buf, size_t count,1727			  u32 reg)1728{1729	long value;1730	int ret;1731 1732	if (reg >= GSS_NUM_REGS)1733		return -EINVAL;1734 1735	ret = kstrtol(buf, 16, &value);1736	if (ret) {1737		count = -EFAULT;1738		goto err;1739	}1740 1741	ret = zynqmp_pm_write_pggs(reg, value);1742	if (ret)1743		count = -EFAULT;1744 1745err:1746	return count;1747}1748 1749#define PGGS0_SHOW(N)						\1750	ssize_t pggs##N##_show(struct device *device,		\1751			       struct device_attribute *attr,	\1752			       char *buf)			\1753	{							\1754		return pggs_show(device, attr, buf, N);		\1755	}1756 1757#define PGGS0_STORE(N)						\1758	ssize_t pggs##N##_store(struct device *device,		\1759				struct device_attribute *attr,	\1760				const char *buf,		\1761				size_t count)			\1762	{							\1763		return pggs_store(device, attr, buf, count, N);	\1764	}1765 1766/* PGGS register show functions */1767static PGGS0_SHOW(0);1768static PGGS0_SHOW(1);1769static PGGS0_SHOW(2);1770static PGGS0_SHOW(3);1771 1772/* PGGS register store functions */1773static PGGS0_STORE(0);1774static PGGS0_STORE(1);1775static PGGS0_STORE(2);1776static PGGS0_STORE(3);1777 1778/* GGS register attributes */1779static DEVICE_ATTR_RW(ggs0);1780static DEVICE_ATTR_RW(ggs1);1781static DEVICE_ATTR_RW(ggs2);1782static DEVICE_ATTR_RW(ggs3);1783 1784/* PGGS register attributes */1785static DEVICE_ATTR_RW(pggs0);1786static DEVICE_ATTR_RW(pggs1);1787static DEVICE_ATTR_RW(pggs2);1788static DEVICE_ATTR_RW(pggs3);1789 1790static ssize_t feature_config_id_show(struct device *device,1791				      struct device_attribute *attr,1792				      char *buf)1793{1794	struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);1795 1796	return sysfs_emit(buf, "%d\n", devinfo->feature_conf_id);1797}1798 1799static ssize_t feature_config_id_store(struct device *device,1800				       struct device_attribute *attr,1801				       const char *buf, size_t count)1802{1803	u32 config_id;1804	int ret;1805	struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);1806 1807	if (!buf)1808		return -EINVAL;1809 1810	ret = kstrtou32(buf, 10, &config_id);1811	if (ret)1812		return ret;1813 1814	devinfo->feature_conf_id = config_id;1815 1816	return count;1817}1818 1819static DEVICE_ATTR_RW(feature_config_id);1820 1821static ssize_t feature_config_value_show(struct device *device,1822					 struct device_attribute *attr,1823					 char *buf)1824{1825	int ret;1826	u32 ret_payload[PAYLOAD_ARG_CNT];1827	struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);1828 1829	ret = zynqmp_pm_get_feature_config(devinfo->feature_conf_id,1830					   ret_payload);1831	if (ret)1832		return ret;1833 1834	return sysfs_emit(buf, "%d\n", ret_payload[1]);1835}1836 1837static ssize_t feature_config_value_store(struct device *device,1838					  struct device_attribute *attr,1839					  const char *buf, size_t count)1840{1841	u32 value;1842	int ret;1843	struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);1844 1845	if (!buf)1846		return -EINVAL;1847 1848	ret = kstrtou32(buf, 10, &value);1849	if (ret)1850		return ret;1851 1852	ret = zynqmp_pm_set_feature_config(devinfo->feature_conf_id,1853					   value);1854	if (ret)1855		return ret;1856 1857	return count;1858}1859 1860static DEVICE_ATTR_RW(feature_config_value);1861 1862static struct attribute *zynqmp_firmware_attrs[] = {1863	&dev_attr_ggs0.attr,1864	&dev_attr_ggs1.attr,1865	&dev_attr_ggs2.attr,1866	&dev_attr_ggs3.attr,1867	&dev_attr_pggs0.attr,1868	&dev_attr_pggs1.attr,1869	&dev_attr_pggs2.attr,1870	&dev_attr_pggs3.attr,1871	&dev_attr_shutdown_scope.attr,1872	&dev_attr_health_status.attr,1873	&dev_attr_feature_config_id.attr,1874	&dev_attr_feature_config_value.attr,1875	NULL,1876};1877 1878ATTRIBUTE_GROUPS(zynqmp_firmware);1879 1880static int zynqmp_firmware_probe(struct platform_device *pdev)1881{1882	struct device *dev = &pdev->dev;1883	struct zynqmp_devinfo *devinfo;1884	int ret;1885 1886	ret = get_set_conduit_method(dev->of_node);1887	if (ret)1888		return ret;1889 1890	ret = do_feature_check_call(PM_FEATURE_CHECK);1891	if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1))1892		feature_check_enabled = true;1893 1894	devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL);1895	if (!devinfo)1896		return -ENOMEM;1897 1898	devinfo->dev = dev;1899 1900	platform_set_drvdata(pdev, devinfo);1901 1902	/* Check PM API version number */1903	ret = zynqmp_pm_get_api_version(&pm_api_version);1904	if (ret)1905		return ret;1906 1907	if (pm_api_version < ZYNQMP_PM_VERSION) {1908		panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",1909		      __func__,1910		      ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR,1911		      pm_api_version >> 16, pm_api_version & 0xFFFF);1912	}1913 1914	pr_info("%s Platform Management API v%d.%d\n", __func__,1915		pm_api_version >> 16, pm_api_version & 0xFFFF);1916 1917	/* Get the Family code and sub family code of platform */1918	ret = zynqmp_pm_get_family_info(&pm_family_code, &pm_sub_family_code);1919	if (ret < 0)1920		return ret;1921 1922	/* Check trustzone version number */1923	ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);1924	if (ret)1925		panic("Legacy trustzone found without version support\n");1926 1927	if (pm_tz_version < ZYNQMP_TZ_VERSION)1928		panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",1929		      __func__,1930		      ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR,1931		      pm_tz_version >> 16, pm_tz_version & 0xFFFF);1932 1933	pr_info("%s Trustzone version v%d.%d\n", __func__,1934		pm_tz_version >> 16, pm_tz_version & 0xFFFF);1935 1936	ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,1937			      ARRAY_SIZE(firmware_devs), NULL, 0, NULL);1938	if (ret) {1939		dev_err(&pdev->dev, "failed to add MFD devices %d\n", ret);1940		return ret;1941	}1942 1943	zynqmp_pm_api_debugfs_init();1944 1945	if (pm_family_code == VERSAL_FAMILY_CODE) {1946		em_dev = platform_device_register_data(&pdev->dev, "xlnx_event_manager",1947						       -1, NULL, 0);1948		if (IS_ERR(em_dev))1949			dev_err_probe(&pdev->dev, PTR_ERR(em_dev), "EM register fail with error\n");1950	}1951 1952	return of_platform_populate(dev->of_node, NULL, NULL, dev);1953}1954 1955static void zynqmp_firmware_remove(struct platform_device *pdev)1956{1957	struct pm_api_feature_data *feature_data;1958	struct hlist_node *tmp;1959	int i;1960 1961	mfd_remove_devices(&pdev->dev);1962	zynqmp_pm_api_debugfs_exit();1963 1964	hash_for_each_safe(pm_api_features_map, i, tmp, feature_data, hentry) {1965		hash_del(&feature_data->hentry);1966		kfree(feature_data);1967	}1968 1969	platform_device_unregister(em_dev);1970}1971 1972static const struct of_device_id zynqmp_firmware_of_match[] = {1973	{.compatible = "xlnx,zynqmp-firmware"},1974	{.compatible = "xlnx,versal-firmware"},1975	{},1976};1977MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);1978 1979static struct platform_driver zynqmp_firmware_driver = {1980	.driver = {1981		.name = "zynqmp_firmware",1982		.of_match_table = zynqmp_firmware_of_match,1983		.dev_groups = zynqmp_firmware_groups,1984	},1985	.probe = zynqmp_firmware_probe,1986	.remove_new = zynqmp_firmware_remove,1987};1988module_platform_driver(zynqmp_firmware_driver);1989