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/mfd/core.h> 18 #include <linux/module.h> 19 #include <linux/of.h> 20 #include <linux/of_platform.h> 21 #include <linux/slab.h> 22 #include <linux/uaccess.h> 23 24 #include <linux/firmware/xlnx-zynqmp.h> 25 #include "zynqmp-debug.h" 26 27 static const struct zynqmp_eemi_ops *eemi_ops_tbl; 28 29 static const struct mfd_cell firmware_devs[] = { 30 { 31 .name = "zynqmp_power_controller", 32 }, 33 }; 34 35 /** 36 * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes 37 * @ret_status: PMUFW return code 38 * 39 * Return: corresponding Linux error code 40 */ 41 static int zynqmp_pm_ret_code(u32 ret_status) 42 { 43 switch (ret_status) { 44 case XST_PM_SUCCESS: 45 case XST_PM_DOUBLE_REQ: 46 return 0; 47 case XST_PM_NO_ACCESS: 48 return -EACCES; 49 case XST_PM_ABORT_SUSPEND: 50 return -ECANCELED; 51 case XST_PM_INTERNAL: 52 case XST_PM_CONFLICT: 53 case XST_PM_INVALID_NODE: 54 default: 55 return -EINVAL; 56 } 57 } 58 59 static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2, 60 u32 *ret_payload) 61 { 62 return -ENODEV; 63 } 64 65 /* 66 * PM function call wrapper 67 * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration 68 */ 69 static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail; 70 71 /** 72 * do_fw_call_smc() - Call system-level platform management layer (SMC) 73 * @arg0: Argument 0 to SMC call 74 * @arg1: Argument 1 to SMC call 75 * @arg2: Argument 2 to SMC call 76 * @ret_payload: Returned value array 77 * 78 * Invoke platform management function via SMC call (no hypervisor present). 79 * 80 * Return: Returns status, either success or error+reason 81 */ 82 static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2, 83 u32 *ret_payload) 84 { 85 struct arm_smccc_res res; 86 87 arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res); 88 89 if (ret_payload) { 90 ret_payload[0] = lower_32_bits(res.a0); 91 ret_payload[1] = upper_32_bits(res.a0); 92 ret_payload[2] = lower_32_bits(res.a1); 93 ret_payload[3] = upper_32_bits(res.a1); 94 } 95 96 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); 97 } 98 99 /** 100 * do_fw_call_hvc() - Call system-level platform management layer (HVC) 101 * @arg0: Argument 0 to HVC call 102 * @arg1: Argument 1 to HVC call 103 * @arg2: Argument 2 to HVC call 104 * @ret_payload: Returned value array 105 * 106 * Invoke platform management function via HVC 107 * HVC-based for communication through hypervisor 108 * (no direct communication with ATF). 109 * 110 * Return: Returns status, either success or error+reason 111 */ 112 static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2, 113 u32 *ret_payload) 114 { 115 struct arm_smccc_res res; 116 117 arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res); 118 119 if (ret_payload) { 120 ret_payload[0] = lower_32_bits(res.a0); 121 ret_payload[1] = upper_32_bits(res.a0); 122 ret_payload[2] = lower_32_bits(res.a1); 123 ret_payload[3] = upper_32_bits(res.a1); 124 } 125 126 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); 127 } 128 129 /** 130 * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer 131 * caller function depending on the configuration 132 * @pm_api_id: Requested PM-API call 133 * @arg0: Argument 0 to requested PM-API call 134 * @arg1: Argument 1 to requested PM-API call 135 * @arg2: Argument 2 to requested PM-API call 136 * @arg3: Argument 3 to requested PM-API call 137 * @ret_payload: Returned value array 138 * 139 * Invoke platform management function for SMC or HVC call, depending on 140 * configuration. 141 * Following SMC Calling Convention (SMCCC) for SMC64: 142 * Pm Function Identifier, 143 * PM_SIP_SVC + PM_API_ID = 144 * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) 145 * ((SMC_64) << FUNCID_CC_SHIFT) 146 * ((SIP_START) << FUNCID_OEN_SHIFT) 147 * ((PM_API_ID) & FUNCID_NUM_MASK)) 148 * 149 * PM_SIP_SVC - Registered ZynqMP SIP Service Call. 150 * PM_API_ID - Platform Management API ID. 151 * 152 * Return: Returns status, either success or error+reason 153 */ 154 int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1, 155 u32 arg2, u32 arg3, u32 *ret_payload) 156 { 157 /* 158 * Added SIP service call Function Identifier 159 * Make sure to stay in x0 register 160 */ 161 u64 smc_arg[4]; 162 163 smc_arg[0] = PM_SIP_SVC | pm_api_id; 164 smc_arg[1] = ((u64)arg1 << 32) | arg0; 165 smc_arg[2] = ((u64)arg3 << 32) | arg2; 166 167 return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload); 168 } 169 170 static u32 pm_api_version; 171 static u32 pm_tz_version; 172 173 /** 174 * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware 175 * @version: Returned version value 176 * 177 * Return: Returns status, either success or error+reason 178 */ 179 static int zynqmp_pm_get_api_version(u32 *version) 180 { 181 u32 ret_payload[PAYLOAD_ARG_CNT]; 182 int ret; 183 184 if (!version) 185 return -EINVAL; 186 187 /* Check is PM API version already verified */ 188 if (pm_api_version > 0) { 189 *version = pm_api_version; 190 return 0; 191 } 192 ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload); 193 *version = ret_payload[1]; 194 195 return ret; 196 } 197 198 /** 199 * zynqmp_pm_get_chipid - Get silicon ID registers 200 * @idcode: IDCODE register 201 * @version: version register 202 * 203 * Return: Returns the status of the operation and the idcode and version 204 * registers in @idcode and @version. 205 */ 206 static int zynqmp_pm_get_chipid(u32 *idcode, u32 *version) 207 { 208 u32 ret_payload[PAYLOAD_ARG_CNT]; 209 int ret; 210 211 if (!idcode || !version) 212 return -EINVAL; 213 214 ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); 215 *idcode = ret_payload[1]; 216 *version = ret_payload[2]; 217 218 return ret; 219 } 220 221 /** 222 * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version 223 * @version: Returned version value 224 * 225 * Return: Returns status, either success or error+reason 226 */ 227 static int zynqmp_pm_get_trustzone_version(u32 *version) 228 { 229 u32 ret_payload[PAYLOAD_ARG_CNT]; 230 int ret; 231 232 if (!version) 233 return -EINVAL; 234 235 /* Check is PM trustzone version already verified */ 236 if (pm_tz_version > 0) { 237 *version = pm_tz_version; 238 return 0; 239 } 240 ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0, 241 0, 0, ret_payload); 242 *version = ret_payload[1]; 243 244 return ret; 245 } 246 247 /** 248 * get_set_conduit_method() - Choose SMC or HVC based communication 249 * @np: Pointer to the device_node structure 250 * 251 * Use SMC or HVC-based functions to communicate with EL2/EL3. 252 * 253 * Return: Returns 0 on success or error code 254 */ 255 static int get_set_conduit_method(struct device_node *np) 256 { 257 const char *method; 258 259 if (of_property_read_string(np, "method", &method)) { 260 pr_warn("%s missing \"method\" property\n", __func__); 261 return -ENXIO; 262 } 263 264 if (!strcmp("hvc", method)) { 265 do_fw_call = do_fw_call_hvc; 266 } else if (!strcmp("smc", method)) { 267 do_fw_call = do_fw_call_smc; 268 } else { 269 pr_warn("%s Invalid \"method\" property: %s\n", 270 __func__, method); 271 return -EINVAL; 272 } 273 274 return 0; 275 } 276 277 /** 278 * zynqmp_pm_query_data() - Get query data from firmware 279 * @qdata: Variable to the zynqmp_pm_query_data structure 280 * @out: Returned output value 281 * 282 * Return: Returns status, either success or error+reason 283 */ 284 static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out) 285 { 286 int ret; 287 288 ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1, 289 qdata.arg2, qdata.arg3, out); 290 291 /* 292 * For clock name query, all bytes in SMC response are clock name 293 * characters and return code is always success. For invalid clocks, 294 * clock name bytes would be zeros. 295 */ 296 return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret; 297 } 298 299 /** 300 * zynqmp_pm_clock_enable() - Enable the clock for given id 301 * @clock_id: ID of the clock to be enabled 302 * 303 * This function is used by master to enable the clock 304 * including peripherals and PLL clocks. 305 * 306 * Return: Returns status, either success or error+reason 307 */ 308 static int zynqmp_pm_clock_enable(u32 clock_id) 309 { 310 return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL); 311 } 312 313 /** 314 * zynqmp_pm_clock_disable() - Disable the clock for given id 315 * @clock_id: ID of the clock to be disable 316 * 317 * This function is used by master to disable the clock 318 * including peripherals and PLL clocks. 319 * 320 * Return: Returns status, either success or error+reason 321 */ 322 static int zynqmp_pm_clock_disable(u32 clock_id) 323 { 324 return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL); 325 } 326 327 /** 328 * zynqmp_pm_clock_getstate() - Get the clock state for given id 329 * @clock_id: ID of the clock to be queried 330 * @state: 1/0 (Enabled/Disabled) 331 * 332 * This function is used by master to get the state of clock 333 * including peripherals and PLL clocks. 334 * 335 * Return: Returns status, either success or error+reason 336 */ 337 static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state) 338 { 339 u32 ret_payload[PAYLOAD_ARG_CNT]; 340 int ret; 341 342 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0, 343 0, 0, ret_payload); 344 *state = ret_payload[1]; 345 346 return ret; 347 } 348 349 /** 350 * zynqmp_pm_clock_setdivider() - Set the clock divider for given id 351 * @clock_id: ID of the clock 352 * @divider: divider value 353 * 354 * This function is used by master to set divider for any clock 355 * to achieve desired rate. 356 * 357 * Return: Returns status, either success or error+reason 358 */ 359 static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider) 360 { 361 return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider, 362 0, 0, NULL); 363 } 364 365 /** 366 * zynqmp_pm_clock_getdivider() - Get the clock divider for given id 367 * @clock_id: ID of the clock 368 * @divider: divider value 369 * 370 * This function is used by master to get divider values 371 * for any clock. 372 * 373 * Return: Returns status, either success or error+reason 374 */ 375 static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider) 376 { 377 u32 ret_payload[PAYLOAD_ARG_CNT]; 378 int ret; 379 380 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0, 381 0, 0, ret_payload); 382 *divider = ret_payload[1]; 383 384 return ret; 385 } 386 387 /** 388 * zynqmp_pm_clock_setrate() - Set the clock rate for given id 389 * @clock_id: ID of the clock 390 * @rate: rate value in hz 391 * 392 * This function is used by master to set rate for any clock. 393 * 394 * Return: Returns status, either success or error+reason 395 */ 396 static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate) 397 { 398 return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id, 399 lower_32_bits(rate), 400 upper_32_bits(rate), 401 0, NULL); 402 } 403 404 /** 405 * zynqmp_pm_clock_getrate() - Get the clock rate for given id 406 * @clock_id: ID of the clock 407 * @rate: rate value in hz 408 * 409 * This function is used by master to get rate 410 * for any clock. 411 * 412 * Return: Returns status, either success or error+reason 413 */ 414 static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate) 415 { 416 u32 ret_payload[PAYLOAD_ARG_CNT]; 417 int ret; 418 419 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0, 420 0, 0, ret_payload); 421 *rate = ((u64)ret_payload[2] << 32) | ret_payload[1]; 422 423 return ret; 424 } 425 426 /** 427 * zynqmp_pm_clock_setparent() - Set the clock parent for given id 428 * @clock_id: ID of the clock 429 * @parent_id: parent id 430 * 431 * This function is used by master to set parent for any clock. 432 * 433 * Return: Returns status, either success or error+reason 434 */ 435 static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id) 436 { 437 return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id, 438 parent_id, 0, 0, NULL); 439 } 440 441 /** 442 * zynqmp_pm_clock_getparent() - Get the clock parent for given id 443 * @clock_id: ID of the clock 444 * @parent_id: parent id 445 * 446 * This function is used by master to get parent index 447 * for any clock. 448 * 449 * Return: Returns status, either success or error+reason 450 */ 451 static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id) 452 { 453 u32 ret_payload[PAYLOAD_ARG_CNT]; 454 int ret; 455 456 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0, 457 0, 0, ret_payload); 458 *parent_id = ret_payload[1]; 459 460 return ret; 461 } 462 463 /** 464 * zynqmp_is_valid_ioctl() - Check whether IOCTL ID is valid or not 465 * @ioctl_id: IOCTL ID 466 * 467 * Return: 1 if IOCTL is valid else 0 468 */ 469 static inline int zynqmp_is_valid_ioctl(u32 ioctl_id) 470 { 471 switch (ioctl_id) { 472 case IOCTL_SET_PLL_FRAC_MODE: 473 case IOCTL_GET_PLL_FRAC_MODE: 474 case IOCTL_SET_PLL_FRAC_DATA: 475 case IOCTL_GET_PLL_FRAC_DATA: 476 return 1; 477 default: 478 return 0; 479 } 480 } 481 482 /** 483 * zynqmp_pm_ioctl() - PM IOCTL API for device control and configs 484 * @node_id: Node ID of the device 485 * @ioctl_id: ID of the requested IOCTL 486 * @arg1: Argument 1 to requested IOCTL call 487 * @arg2: Argument 2 to requested IOCTL call 488 * @out: Returned output value 489 * 490 * This function calls IOCTL to firmware for device control and configuration. 491 * 492 * Return: Returns status, either success or error+reason 493 */ 494 static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, 495 u32 *out) 496 { 497 if (!zynqmp_is_valid_ioctl(ioctl_id)) 498 return -EINVAL; 499 500 return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, ioctl_id, 501 arg1, arg2, out); 502 } 503 504 /** 505 * zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release) 506 * @reset: Reset to be configured 507 * @assert_flag: Flag stating should reset be asserted (1) or 508 * released (0) 509 * 510 * Return: Returns status, either success or error+reason 511 */ 512 static int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset, 513 const enum zynqmp_pm_reset_action assert_flag) 514 { 515 return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, reset, assert_flag, 516 0, 0, NULL); 517 } 518 519 /** 520 * zynqmp_pm_reset_get_status - Get status of the reset 521 * @reset: Reset whose status should be returned 522 * @status: Returned status 523 * 524 * Return: Returns status, either success or error+reason 525 */ 526 static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, 527 u32 *status) 528 { 529 u32 ret_payload[PAYLOAD_ARG_CNT]; 530 int ret; 531 532 if (!status) 533 return -EINVAL; 534 535 ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, reset, 0, 536 0, 0, ret_payload); 537 *status = ret_payload[1]; 538 539 return ret; 540 } 541 542 /** 543 * zynqmp_pm_fpga_load - Perform the fpga load 544 * @address: Address to write to 545 * @size: pl bitstream size 546 * @flags: Bitstream type 547 * -XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration 548 * -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration 549 * 550 * This function provides access to pmufw. To transfer 551 * the required bitstream into PL. 552 * 553 * Return: Returns status, either success or error+reason 554 */ 555 static int zynqmp_pm_fpga_load(const u64 address, const u32 size, 556 const u32 flags) 557 { 558 return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address), 559 upper_32_bits(address), size, flags, NULL); 560 } 561 562 /** 563 * zynqmp_pm_fpga_get_status - Read value from PCAP status register 564 * @value: Value to read 565 * 566 * This function provides access to the pmufw to get the PCAP 567 * status 568 * 569 * Return: Returns status, either success or error+reason 570 */ 571 static int zynqmp_pm_fpga_get_status(u32 *value) 572 { 573 u32 ret_payload[PAYLOAD_ARG_CNT]; 574 int ret; 575 576 if (!value) 577 return -EINVAL; 578 579 ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload); 580 *value = ret_payload[1]; 581 582 return ret; 583 } 584 585 /** 586 * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller 587 * master has initialized its own power management 588 * 589 * This API function is to be used for notify the power management controller 590 * about the completed power management initialization. 591 * 592 * Return: Returns status, either success or error+reason 593 */ 594 static int zynqmp_pm_init_finalize(void) 595 { 596 return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, 0, 0, 0, 0, NULL); 597 } 598 599 /** 600 * zynqmp_pm_set_suspend_mode() - Set system suspend mode 601 * @mode: Mode to set for system suspend 602 * 603 * This API function is used to set mode of system suspend. 604 * 605 * Return: Returns status, either success or error+reason 606 */ 607 static int zynqmp_pm_set_suspend_mode(u32 mode) 608 { 609 return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, mode, 0, 0, 0, NULL); 610 } 611 612 /** 613 * zynqmp_pm_request_node() - Request a node with specific capabilities 614 * @node: Node ID of the slave 615 * @capabilities: Requested capabilities of the slave 616 * @qos: Quality of service (not supported) 617 * @ack: Flag to specify whether acknowledge is requested 618 * 619 * This function is used by master to request particular node from firmware. 620 * Every master must request node before using it. 621 * 622 * Return: Returns status, either success or error+reason 623 */ 624 static int zynqmp_pm_request_node(const u32 node, const u32 capabilities, 625 const u32 qos, 626 const enum zynqmp_pm_request_ack ack) 627 { 628 return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, node, capabilities, 629 qos, ack, NULL); 630 } 631 632 /** 633 * zynqmp_pm_release_node() - Release a node 634 * @node: Node ID of the slave 635 * 636 * This function is used by master to inform firmware that master 637 * has released node. Once released, master must not use that node 638 * without re-request. 639 * 640 * Return: Returns status, either success or error+reason 641 */ 642 static int zynqmp_pm_release_node(const u32 node) 643 { 644 return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, node, 0, 0, 0, NULL); 645 } 646 647 /** 648 * zynqmp_pm_set_requirement() - PM call to set requirement for PM slaves 649 * @node: Node ID of the slave 650 * @capabilities: Requested capabilities of the slave 651 * @qos: Quality of service (not supported) 652 * @ack: Flag to specify whether acknowledge is requested 653 * 654 * This API function is to be used for slaves a PU already has requested 655 * to change its capabilities. 656 * 657 * Return: Returns status, either success or error+reason 658 */ 659 static int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities, 660 const u32 qos, 661 const enum zynqmp_pm_request_ack ack) 662 { 663 return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, node, capabilities, 664 qos, ack, NULL); 665 } 666 667 static const struct zynqmp_eemi_ops eemi_ops = { 668 .get_api_version = zynqmp_pm_get_api_version, 669 .get_chipid = zynqmp_pm_get_chipid, 670 .query_data = zynqmp_pm_query_data, 671 .clock_enable = zynqmp_pm_clock_enable, 672 .clock_disable = zynqmp_pm_clock_disable, 673 .clock_getstate = zynqmp_pm_clock_getstate, 674 .clock_setdivider = zynqmp_pm_clock_setdivider, 675 .clock_getdivider = zynqmp_pm_clock_getdivider, 676 .clock_setrate = zynqmp_pm_clock_setrate, 677 .clock_getrate = zynqmp_pm_clock_getrate, 678 .clock_setparent = zynqmp_pm_clock_setparent, 679 .clock_getparent = zynqmp_pm_clock_getparent, 680 .ioctl = zynqmp_pm_ioctl, 681 .reset_assert = zynqmp_pm_reset_assert, 682 .reset_get_status = zynqmp_pm_reset_get_status, 683 .init_finalize = zynqmp_pm_init_finalize, 684 .set_suspend_mode = zynqmp_pm_set_suspend_mode, 685 .request_node = zynqmp_pm_request_node, 686 .release_node = zynqmp_pm_release_node, 687 .set_requirement = zynqmp_pm_set_requirement, 688 .fpga_load = zynqmp_pm_fpga_load, 689 .fpga_get_status = zynqmp_pm_fpga_get_status, 690 }; 691 692 /** 693 * zynqmp_pm_get_eemi_ops - Get eemi ops functions 694 * 695 * Return: Pointer of eemi_ops structure 696 */ 697 const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) 698 { 699 if (eemi_ops_tbl) 700 return eemi_ops_tbl; 701 else 702 return ERR_PTR(-EPROBE_DEFER); 703 704 } 705 EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); 706 707 static int zynqmp_firmware_probe(struct platform_device *pdev) 708 { 709 struct device *dev = &pdev->dev; 710 struct device_node *np; 711 int ret; 712 713 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp"); 714 if (!np) 715 return 0; 716 of_node_put(np); 717 718 ret = get_set_conduit_method(dev->of_node); 719 if (ret) 720 return ret; 721 722 /* Check PM API version number */ 723 zynqmp_pm_get_api_version(&pm_api_version); 724 if (pm_api_version < ZYNQMP_PM_VERSION) { 725 panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n", 726 __func__, 727 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR, 728 pm_api_version >> 16, pm_api_version & 0xFFFF); 729 } 730 731 pr_info("%s Platform Management API v%d.%d\n", __func__, 732 pm_api_version >> 16, pm_api_version & 0xFFFF); 733 734 /* Check trustzone version number */ 735 ret = zynqmp_pm_get_trustzone_version(&pm_tz_version); 736 if (ret) 737 panic("Legacy trustzone found without version support\n"); 738 739 if (pm_tz_version < ZYNQMP_TZ_VERSION) 740 panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n", 741 __func__, 742 ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR, 743 pm_tz_version >> 16, pm_tz_version & 0xFFFF); 744 745 pr_info("%s Trustzone version v%d.%d\n", __func__, 746 pm_tz_version >> 16, pm_tz_version & 0xFFFF); 747 748 /* Assign eemi_ops_table */ 749 eemi_ops_tbl = &eemi_ops; 750 751 zynqmp_pm_api_debugfs_init(); 752 753 ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs, 754 ARRAY_SIZE(firmware_devs), NULL, 0, NULL); 755 if (ret) { 756 dev_err(&pdev->dev, "failed to add MFD devices %d\n", ret); 757 return ret; 758 } 759 760 return of_platform_populate(dev->of_node, NULL, NULL, dev); 761 } 762 763 static int zynqmp_firmware_remove(struct platform_device *pdev) 764 { 765 mfd_remove_devices(&pdev->dev); 766 zynqmp_pm_api_debugfs_exit(); 767 768 return 0; 769 } 770 771 static const struct of_device_id zynqmp_firmware_of_match[] = { 772 {.compatible = "xlnx,zynqmp-firmware"}, 773 {}, 774 }; 775 MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match); 776 777 static struct platform_driver zynqmp_firmware_driver = { 778 .driver = { 779 .name = "zynqmp_firmware", 780 .of_match_table = zynqmp_firmware_of_match, 781 }, 782 .probe = zynqmp_firmware_probe, 783 .remove = zynqmp_firmware_remove, 784 }; 785 module_platform_driver(zynqmp_firmware_driver); 786