1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Xilinx Zynq MPSoC Firmware layer 4 * 5 * Copyright (C) 2014-2018 Xilinx, Inc. 6 * 7 * Michal Simek <michal.simek@xilinx.com> 8 * Davorin Mista <davorin.mista@aggios.com> 9 * Jolly Shah <jollys@xilinx.com> 10 * Rajan Vaja <rajanv@xilinx.com> 11 */ 12 13 #include <linux/arm-smccc.h> 14 #include <linux/compiler.h> 15 #include <linux/device.h> 16 #include <linux/init.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/of_platform.h> 20 #include <linux/slab.h> 21 #include <linux/uaccess.h> 22 23 #include <linux/firmware/xlnx-zynqmp.h> 24 #include "zynqmp-debug.h" 25 26 /** 27 * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes 28 * @ret_status: PMUFW return code 29 * 30 * Return: corresponding Linux error code 31 */ 32 static int zynqmp_pm_ret_code(u32 ret_status) 33 { 34 switch (ret_status) { 35 case XST_PM_SUCCESS: 36 case XST_PM_DOUBLE_REQ: 37 return 0; 38 case XST_PM_NO_ACCESS: 39 return -EACCES; 40 case XST_PM_ABORT_SUSPEND: 41 return -ECANCELED; 42 case XST_PM_INTERNAL: 43 case XST_PM_CONFLICT: 44 case XST_PM_INVALID_NODE: 45 default: 46 return -EINVAL; 47 } 48 } 49 50 static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2, 51 u32 *ret_payload) 52 { 53 return -ENODEV; 54 } 55 56 /* 57 * PM function call wrapper 58 * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration 59 */ 60 static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail; 61 62 /** 63 * do_fw_call_smc() - Call system-level platform management layer (SMC) 64 * @arg0: Argument 0 to SMC call 65 * @arg1: Argument 1 to SMC call 66 * @arg2: Argument 2 to SMC call 67 * @ret_payload: Returned value array 68 * 69 * Invoke platform management function via SMC call (no hypervisor present). 70 * 71 * Return: Returns status, either success or error+reason 72 */ 73 static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2, 74 u32 *ret_payload) 75 { 76 struct arm_smccc_res res; 77 78 arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res); 79 80 if (ret_payload) { 81 ret_payload[0] = lower_32_bits(res.a0); 82 ret_payload[1] = upper_32_bits(res.a0); 83 ret_payload[2] = lower_32_bits(res.a1); 84 ret_payload[3] = upper_32_bits(res.a1); 85 } 86 87 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); 88 } 89 90 /** 91 * do_fw_call_hvc() - Call system-level platform management layer (HVC) 92 * @arg0: Argument 0 to HVC call 93 * @arg1: Argument 1 to HVC call 94 * @arg2: Argument 2 to HVC call 95 * @ret_payload: Returned value array 96 * 97 * Invoke platform management function via HVC 98 * HVC-based for communication through hypervisor 99 * (no direct communication with ATF). 100 * 101 * Return: Returns status, either success or error+reason 102 */ 103 static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2, 104 u32 *ret_payload) 105 { 106 struct arm_smccc_res res; 107 108 arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res); 109 110 if (ret_payload) { 111 ret_payload[0] = lower_32_bits(res.a0); 112 ret_payload[1] = upper_32_bits(res.a0); 113 ret_payload[2] = lower_32_bits(res.a1); 114 ret_payload[3] = upper_32_bits(res.a1); 115 } 116 117 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); 118 } 119 120 /** 121 * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer 122 * caller function depending on the configuration 123 * @pm_api_id: Requested PM-API call 124 * @arg0: Argument 0 to requested PM-API call 125 * @arg1: Argument 1 to requested PM-API call 126 * @arg2: Argument 2 to requested PM-API call 127 * @arg3: Argument 3 to requested PM-API call 128 * @ret_payload: Returned value array 129 * 130 * Invoke platform management function for SMC or HVC call, depending on 131 * configuration. 132 * Following SMC Calling Convention (SMCCC) for SMC64: 133 * Pm Function Identifier, 134 * PM_SIP_SVC + PM_API_ID = 135 * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) 136 * ((SMC_64) << FUNCID_CC_SHIFT) 137 * ((SIP_START) << FUNCID_OEN_SHIFT) 138 * ((PM_API_ID) & FUNCID_NUM_MASK)) 139 * 140 * PM_SIP_SVC - Registered ZynqMP SIP Service Call. 141 * PM_API_ID - Platform Management API ID. 142 * 143 * Return: Returns status, either success or error+reason 144 */ 145 int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1, 146 u32 arg2, u32 arg3, u32 *ret_payload) 147 { 148 /* 149 * Added SIP service call Function Identifier 150 * Make sure to stay in x0 register 151 */ 152 u64 smc_arg[4]; 153 154 smc_arg[0] = PM_SIP_SVC | pm_api_id; 155 smc_arg[1] = ((u64)arg1 << 32) | arg0; 156 smc_arg[2] = ((u64)arg3 << 32) | arg2; 157 158 return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload); 159 } 160 161 static u32 pm_api_version; 162 static u32 pm_tz_version; 163 164 /** 165 * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware 166 * @version: Returned version value 167 * 168 * Return: Returns status, either success or error+reason 169 */ 170 static int zynqmp_pm_get_api_version(u32 *version) 171 { 172 u32 ret_payload[PAYLOAD_ARG_CNT]; 173 int ret; 174 175 if (!version) 176 return -EINVAL; 177 178 /* Check is PM API version already verified */ 179 if (pm_api_version > 0) { 180 *version = pm_api_version; 181 return 0; 182 } 183 ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload); 184 *version = ret_payload[1]; 185 186 return ret; 187 } 188 189 /** 190 * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version 191 * @version: Returned version value 192 * 193 * Return: Returns status, either success or error+reason 194 */ 195 static int zynqmp_pm_get_trustzone_version(u32 *version) 196 { 197 u32 ret_payload[PAYLOAD_ARG_CNT]; 198 int ret; 199 200 if (!version) 201 return -EINVAL; 202 203 /* Check is PM trustzone version already verified */ 204 if (pm_tz_version > 0) { 205 *version = pm_tz_version; 206 return 0; 207 } 208 ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0, 209 0, 0, ret_payload); 210 *version = ret_payload[1]; 211 212 return ret; 213 } 214 215 /** 216 * get_set_conduit_method() - Choose SMC or HVC based communication 217 * @np: Pointer to the device_node structure 218 * 219 * Use SMC or HVC-based functions to communicate with EL2/EL3. 220 * 221 * Return: Returns 0 on success or error code 222 */ 223 static int get_set_conduit_method(struct device_node *np) 224 { 225 const char *method; 226 227 if (of_property_read_string(np, "method", &method)) { 228 pr_warn("%s missing \"method\" property\n", __func__); 229 return -ENXIO; 230 } 231 232 if (!strcmp("hvc", method)) { 233 do_fw_call = do_fw_call_hvc; 234 } else if (!strcmp("smc", method)) { 235 do_fw_call = do_fw_call_smc; 236 } else { 237 pr_warn("%s Invalid \"method\" property: %s\n", 238 __func__, method); 239 return -EINVAL; 240 } 241 242 return 0; 243 } 244 245 /** 246 * zynqmp_pm_query_data() - Get query data from firmware 247 * @qdata: Variable to the zynqmp_pm_query_data structure 248 * @out: Returned output value 249 * 250 * Return: Returns status, either success or error+reason 251 */ 252 static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out) 253 { 254 int ret; 255 256 ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1, 257 qdata.arg2, qdata.arg3, out); 258 259 /* 260 * For clock name query, all bytes in SMC response are clock name 261 * characters and return code is always success. For invalid clocks, 262 * clock name bytes would be zeros. 263 */ 264 return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret; 265 } 266 267 /** 268 * zynqmp_pm_clock_enable() - Enable the clock for given id 269 * @clock_id: ID of the clock to be enabled 270 * 271 * This function is used by master to enable the clock 272 * including peripherals and PLL clocks. 273 * 274 * Return: Returns status, either success or error+reason 275 */ 276 static int zynqmp_pm_clock_enable(u32 clock_id) 277 { 278 return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL); 279 } 280 281 /** 282 * zynqmp_pm_clock_disable() - Disable the clock for given id 283 * @clock_id: ID of the clock to be disable 284 * 285 * This function is used by master to disable the clock 286 * including peripherals and PLL clocks. 287 * 288 * Return: Returns status, either success or error+reason 289 */ 290 static int zynqmp_pm_clock_disable(u32 clock_id) 291 { 292 return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL); 293 } 294 295 /** 296 * zynqmp_pm_clock_getstate() - Get the clock state for given id 297 * @clock_id: ID of the clock to be queried 298 * @state: 1/0 (Enabled/Disabled) 299 * 300 * This function is used by master to get the state of clock 301 * including peripherals and PLL clocks. 302 * 303 * Return: Returns status, either success or error+reason 304 */ 305 static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state) 306 { 307 u32 ret_payload[PAYLOAD_ARG_CNT]; 308 int ret; 309 310 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0, 311 0, 0, ret_payload); 312 *state = ret_payload[1]; 313 314 return ret; 315 } 316 317 /** 318 * zynqmp_pm_clock_setdivider() - Set the clock divider for given id 319 * @clock_id: ID of the clock 320 * @divider: divider value 321 * 322 * This function is used by master to set divider for any clock 323 * to achieve desired rate. 324 * 325 * Return: Returns status, either success or error+reason 326 */ 327 static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider) 328 { 329 return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider, 330 0, 0, NULL); 331 } 332 333 /** 334 * zynqmp_pm_clock_getdivider() - Get the clock divider for given id 335 * @clock_id: ID of the clock 336 * @divider: divider value 337 * 338 * This function is used by master to get divider values 339 * for any clock. 340 * 341 * Return: Returns status, either success or error+reason 342 */ 343 static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider) 344 { 345 u32 ret_payload[PAYLOAD_ARG_CNT]; 346 int ret; 347 348 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0, 349 0, 0, ret_payload); 350 *divider = ret_payload[1]; 351 352 return ret; 353 } 354 355 /** 356 * zynqmp_pm_clock_setrate() - Set the clock rate for given id 357 * @clock_id: ID of the clock 358 * @rate: rate value in hz 359 * 360 * This function is used by master to set rate for any clock. 361 * 362 * Return: Returns status, either success or error+reason 363 */ 364 static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate) 365 { 366 return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id, 367 lower_32_bits(rate), 368 upper_32_bits(rate), 369 0, NULL); 370 } 371 372 /** 373 * zynqmp_pm_clock_getrate() - Get the clock rate for given id 374 * @clock_id: ID of the clock 375 * @rate: rate value in hz 376 * 377 * This function is used by master to get rate 378 * for any clock. 379 * 380 * Return: Returns status, either success or error+reason 381 */ 382 static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate) 383 { 384 u32 ret_payload[PAYLOAD_ARG_CNT]; 385 int ret; 386 387 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0, 388 0, 0, ret_payload); 389 *rate = ((u64)ret_payload[2] << 32) | ret_payload[1]; 390 391 return ret; 392 } 393 394 /** 395 * zynqmp_pm_clock_setparent() - Set the clock parent for given id 396 * @clock_id: ID of the clock 397 * @parent_id: parent id 398 * 399 * This function is used by master to set parent for any clock. 400 * 401 * Return: Returns status, either success or error+reason 402 */ 403 static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id) 404 { 405 return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id, 406 parent_id, 0, 0, NULL); 407 } 408 409 /** 410 * zynqmp_pm_clock_getparent() - Get the clock parent for given id 411 * @clock_id: ID of the clock 412 * @parent_id: parent id 413 * 414 * This function is used by master to get parent index 415 * for any clock. 416 * 417 * Return: Returns status, either success or error+reason 418 */ 419 static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id) 420 { 421 u32 ret_payload[PAYLOAD_ARG_CNT]; 422 int ret; 423 424 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0, 425 0, 0, ret_payload); 426 *parent_id = ret_payload[1]; 427 428 return ret; 429 } 430 431 /** 432 * zynqmp_is_valid_ioctl() - Check whether IOCTL ID is valid or not 433 * @ioctl_id: IOCTL ID 434 * 435 * Return: 1 if IOCTL is valid else 0 436 */ 437 static inline int zynqmp_is_valid_ioctl(u32 ioctl_id) 438 { 439 switch (ioctl_id) { 440 case IOCTL_SET_PLL_FRAC_MODE: 441 case IOCTL_GET_PLL_FRAC_MODE: 442 case IOCTL_SET_PLL_FRAC_DATA: 443 case IOCTL_GET_PLL_FRAC_DATA: 444 return 1; 445 default: 446 return 0; 447 } 448 } 449 450 /** 451 * zynqmp_pm_ioctl() - PM IOCTL API for device control and configs 452 * @node_id: Node ID of the device 453 * @ioctl_id: ID of the requested IOCTL 454 * @arg1: Argument 1 to requested IOCTL call 455 * @arg2: Argument 2 to requested IOCTL call 456 * @out: Returned output value 457 * 458 * This function calls IOCTL to firmware for device control and configuration. 459 * 460 * Return: Returns status, either success or error+reason 461 */ 462 static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, 463 u32 *out) 464 { 465 if (!zynqmp_is_valid_ioctl(ioctl_id)) 466 return -EINVAL; 467 468 return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, ioctl_id, 469 arg1, arg2, out); 470 } 471 472 static const struct zynqmp_eemi_ops eemi_ops = { 473 .get_api_version = zynqmp_pm_get_api_version, 474 .query_data = zynqmp_pm_query_data, 475 .clock_enable = zynqmp_pm_clock_enable, 476 .clock_disable = zynqmp_pm_clock_disable, 477 .clock_getstate = zynqmp_pm_clock_getstate, 478 .clock_setdivider = zynqmp_pm_clock_setdivider, 479 .clock_getdivider = zynqmp_pm_clock_getdivider, 480 .clock_setrate = zynqmp_pm_clock_setrate, 481 .clock_getrate = zynqmp_pm_clock_getrate, 482 .clock_setparent = zynqmp_pm_clock_setparent, 483 .clock_getparent = zynqmp_pm_clock_getparent, 484 .ioctl = zynqmp_pm_ioctl, 485 }; 486 487 /** 488 * zynqmp_pm_get_eemi_ops - Get eemi ops functions 489 * 490 * Return: Pointer of eemi_ops structure 491 */ 492 const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) 493 { 494 return &eemi_ops; 495 } 496 EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); 497 498 static int zynqmp_firmware_probe(struct platform_device *pdev) 499 { 500 struct device *dev = &pdev->dev; 501 struct device_node *np; 502 int ret; 503 504 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp"); 505 if (!np) 506 return 0; 507 of_node_put(np); 508 509 ret = get_set_conduit_method(dev->of_node); 510 if (ret) 511 return ret; 512 513 /* Check PM API version number */ 514 zynqmp_pm_get_api_version(&pm_api_version); 515 if (pm_api_version < ZYNQMP_PM_VERSION) { 516 panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n", 517 __func__, 518 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR, 519 pm_api_version >> 16, pm_api_version & 0xFFFF); 520 } 521 522 pr_info("%s Platform Management API v%d.%d\n", __func__, 523 pm_api_version >> 16, pm_api_version & 0xFFFF); 524 525 /* Check trustzone version number */ 526 ret = zynqmp_pm_get_trustzone_version(&pm_tz_version); 527 if (ret) 528 panic("Legacy trustzone found without version support\n"); 529 530 if (pm_tz_version < ZYNQMP_TZ_VERSION) 531 panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n", 532 __func__, 533 ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR, 534 pm_tz_version >> 16, pm_tz_version & 0xFFFF); 535 536 pr_info("%s Trustzone version v%d.%d\n", __func__, 537 pm_tz_version >> 16, pm_tz_version & 0xFFFF); 538 539 zynqmp_pm_api_debugfs_init(); 540 541 return of_platform_populate(dev->of_node, NULL, NULL, dev); 542 } 543 544 static int zynqmp_firmware_remove(struct platform_device *pdev) 545 { 546 zynqmp_pm_api_debugfs_exit(); 547 548 return 0; 549 } 550 551 static const struct of_device_id zynqmp_firmware_of_match[] = { 552 {.compatible = "xlnx,zynqmp-firmware"}, 553 {}, 554 }; 555 MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match); 556 557 static struct platform_driver zynqmp_firmware_driver = { 558 .driver = { 559 .name = "zynqmp_firmware", 560 .of_match_table = zynqmp_firmware_of_match, 561 }, 562 .probe = zynqmp_firmware_probe, 563 .remove = zynqmp_firmware_remove, 564 }; 565 module_platform_driver(zynqmp_firmware_driver); 566