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