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