.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
---|
2 | 2 | /* |
---|
3 | 3 | * Copyright 2013-2016 Freescale Semiconductor Inc. |
---|
| 4 | + * Copyright 2020 NXP |
---|
4 | 5 | * |
---|
5 | 6 | */ |
---|
6 | 7 | #include <linux/kernel.h> |
---|
7 | 8 | #include <linux/fsl/mc.h> |
---|
8 | 9 | |
---|
9 | 10 | #include "fsl-mc-private.h" |
---|
| 11 | + |
---|
| 12 | +/* |
---|
| 13 | + * cache the DPRC version to reduce the number of commands |
---|
| 14 | + * towards the mc firmware |
---|
| 15 | + */ |
---|
| 16 | +static u16 dprc_major_ver; |
---|
| 17 | +static u16 dprc_minor_ver; |
---|
10 | 18 | |
---|
11 | 19 | /** |
---|
12 | 20 | * dprc_open() - Open DPRC object for use |
---|
.. | .. |
---|
71 | 79 | return mc_send_command(mc_io, &cmd); |
---|
72 | 80 | } |
---|
73 | 81 | EXPORT_SYMBOL_GPL(dprc_close); |
---|
| 82 | + |
---|
| 83 | +/** |
---|
| 84 | + * dprc_reset_container - Reset child container. |
---|
| 85 | + * @mc_io: Pointer to MC portal's I/O object |
---|
| 86 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
---|
| 87 | + * @token: Token of DPRC object |
---|
| 88 | + * @child_container_id: ID of the container to reset |
---|
| 89 | + * @options: 32 bit options: |
---|
| 90 | + * - 0 (no bits set) - all the objects inside the container are |
---|
| 91 | + * reset. The child containers are entered recursively and the |
---|
| 92 | + * objects reset. All the objects (including the child containers) |
---|
| 93 | + * are closed. |
---|
| 94 | + * - bit 0 set - all the objects inside the container are reset. |
---|
| 95 | + * However the child containers are not entered recursively. |
---|
| 96 | + * This option is supported for API versions >= 6.5 |
---|
| 97 | + * In case a software context crashes or becomes non-responsive, the parent |
---|
| 98 | + * may wish to reset its resources container before the software context is |
---|
| 99 | + * restarted. |
---|
| 100 | + * |
---|
| 101 | + * This routine informs all objects assigned to the child container that the |
---|
| 102 | + * container is being reset, so they may perform any cleanup operations that are |
---|
| 103 | + * needed. All objects handles that were owned by the child container shall be |
---|
| 104 | + * closed. |
---|
| 105 | + * |
---|
| 106 | + * Note that such request may be submitted even if the child software context |
---|
| 107 | + * has not crashed, but the resulting object cleanup operations will not be |
---|
| 108 | + * aware of that. |
---|
| 109 | + * |
---|
| 110 | + * Return: '0' on Success; Error code otherwise. |
---|
| 111 | + */ |
---|
| 112 | +int dprc_reset_container(struct fsl_mc_io *mc_io, |
---|
| 113 | + u32 cmd_flags, |
---|
| 114 | + u16 token, |
---|
| 115 | + int child_container_id, |
---|
| 116 | + u32 options) |
---|
| 117 | +{ |
---|
| 118 | + struct fsl_mc_command cmd = { 0 }; |
---|
| 119 | + struct dprc_cmd_reset_container *cmd_params; |
---|
| 120 | + u32 cmdid = DPRC_CMDID_RESET_CONT; |
---|
| 121 | + int err; |
---|
| 122 | + |
---|
| 123 | + /* |
---|
| 124 | + * If the DPRC object version was not yet cached, cache it now. |
---|
| 125 | + * Otherwise use the already cached value. |
---|
| 126 | + */ |
---|
| 127 | + if (!dprc_major_ver && !dprc_minor_ver) { |
---|
| 128 | + err = dprc_get_api_version(mc_io, 0, |
---|
| 129 | + &dprc_major_ver, |
---|
| 130 | + &dprc_minor_ver); |
---|
| 131 | + if (err) |
---|
| 132 | + return err; |
---|
| 133 | + } |
---|
| 134 | + |
---|
| 135 | + /* |
---|
| 136 | + * MC API 6.5 introduced a new field in the command used to pass |
---|
| 137 | + * some flags. |
---|
| 138 | + * Bit 0 indicates that the child containers are not recursively reset. |
---|
| 139 | + */ |
---|
| 140 | + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 5)) |
---|
| 141 | + cmdid = DPRC_CMDID_RESET_CONT_V2; |
---|
| 142 | + |
---|
| 143 | + /* prepare command */ |
---|
| 144 | + cmd.header = mc_encode_cmd_header(cmdid, cmd_flags, token); |
---|
| 145 | + cmd_params = (struct dprc_cmd_reset_container *)cmd.params; |
---|
| 146 | + cmd_params->child_container_id = cpu_to_le32(child_container_id); |
---|
| 147 | + cmd_params->options = cpu_to_le32(options); |
---|
| 148 | + |
---|
| 149 | + /* send command to mc*/ |
---|
| 150 | + return mc_send_command(mc_io, &cmd); |
---|
| 151 | +} |
---|
| 152 | +EXPORT_SYMBOL_GPL(dprc_reset_container); |
---|
74 | 153 | |
---|
75 | 154 | /** |
---|
76 | 155 | * dprc_set_irq() - Set IRQ information for the DPRC to trigger an interrupt. |
---|
.. | .. |
---|
281 | 360 | /* retrieve response parameters */ |
---|
282 | 361 | rsp_params = (struct dprc_rsp_get_attributes *)cmd.params; |
---|
283 | 362 | attr->container_id = le32_to_cpu(rsp_params->container_id); |
---|
284 | | - attr->icid = le16_to_cpu(rsp_params->icid); |
---|
| 363 | + attr->icid = le32_to_cpu(rsp_params->icid); |
---|
285 | 364 | attr->options = le32_to_cpu(rsp_params->options); |
---|
286 | 365 | attr->portal_id = le32_to_cpu(rsp_params->portal_id); |
---|
287 | 366 | |
---|
.. | .. |
---|
445 | 524 | struct dprc_rsp_get_obj_region *rsp_params; |
---|
446 | 525 | int err; |
---|
447 | 526 | |
---|
448 | | - /* prepare command */ |
---|
449 | | - cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, |
---|
450 | | - cmd_flags, token); |
---|
| 527 | + /* |
---|
| 528 | + * If the DPRC object version was not yet cached, cache it now. |
---|
| 529 | + * Otherwise use the already cached value. |
---|
| 530 | + */ |
---|
| 531 | + if (!dprc_major_ver && !dprc_minor_ver) { |
---|
| 532 | + err = dprc_get_api_version(mc_io, 0, |
---|
| 533 | + &dprc_major_ver, |
---|
| 534 | + &dprc_minor_ver); |
---|
| 535 | + if (err) |
---|
| 536 | + return err; |
---|
| 537 | + } |
---|
| 538 | + |
---|
| 539 | + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 6)) { |
---|
| 540 | + /* |
---|
| 541 | + * MC API version 6.6 changed the size of the MC portals and software |
---|
| 542 | + * portals to 64K (as implemented by hardware). If older API is in use the |
---|
| 543 | + * size reported is less (64 bytes for mc portals and 4K for software |
---|
| 544 | + * portals). |
---|
| 545 | + */ |
---|
| 546 | + |
---|
| 547 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V3, |
---|
| 548 | + cmd_flags, token); |
---|
| 549 | + |
---|
| 550 | + } else if (dprc_major_ver == 6 && dprc_minor_ver >= 3) { |
---|
| 551 | + /* |
---|
| 552 | + * MC API version 6.3 introduced a new field to the region |
---|
| 553 | + * descriptor: base_address. If the older API is in use then the base |
---|
| 554 | + * address is set to zero to indicate it needs to be obtained elsewhere |
---|
| 555 | + * (typically the device tree). |
---|
| 556 | + */ |
---|
| 557 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2, |
---|
| 558 | + cmd_flags, token); |
---|
| 559 | + } else { |
---|
| 560 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, |
---|
| 561 | + cmd_flags, token); |
---|
| 562 | + } |
---|
| 563 | + |
---|
451 | 564 | cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params; |
---|
452 | 565 | cmd_params->obj_id = cpu_to_le32(obj_id); |
---|
453 | 566 | cmd_params->region_index = region_index; |
---|
.. | .. |
---|
461 | 574 | |
---|
462 | 575 | /* retrieve response parameters */ |
---|
463 | 576 | rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; |
---|
464 | | - region_desc->base_offset = le64_to_cpu(rsp_params->base_addr); |
---|
| 577 | + region_desc->base_offset = le64_to_cpu(rsp_params->base_offset); |
---|
465 | 578 | region_desc->size = le32_to_cpu(rsp_params->size); |
---|
| 579 | + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 3)) |
---|
| 580 | + region_desc->base_address = le64_to_cpu(rsp_params->base_addr); |
---|
| 581 | + else |
---|
| 582 | + region_desc->base_address = 0; |
---|
466 | 583 | |
---|
467 | 584 | return 0; |
---|
468 | 585 | } |
---|
.. | .. |
---|
530 | 647 | |
---|
531 | 648 | return 0; |
---|
532 | 649 | } |
---|
| 650 | + |
---|
| 651 | +/** |
---|
| 652 | + * dprc_get_connection() - Get connected endpoint and link status if connection |
---|
| 653 | + * exists. |
---|
| 654 | + * @mc_io: Pointer to MC portal's I/O object |
---|
| 655 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
---|
| 656 | + * @token: Token of DPRC object |
---|
| 657 | + * @endpoint1: Endpoint 1 configuration parameters |
---|
| 658 | + * @endpoint2: Returned endpoint 2 configuration parameters |
---|
| 659 | + * @state: Returned link state: |
---|
| 660 | + * 1 - link is up; |
---|
| 661 | + * 0 - link is down; |
---|
| 662 | + * -1 - no connection (endpoint2 information is irrelevant) |
---|
| 663 | + * |
---|
| 664 | + * Return: '0' on Success; -ENOTCONN if connection does not exist. |
---|
| 665 | + */ |
---|
| 666 | +int dprc_get_connection(struct fsl_mc_io *mc_io, |
---|
| 667 | + u32 cmd_flags, |
---|
| 668 | + u16 token, |
---|
| 669 | + const struct dprc_endpoint *endpoint1, |
---|
| 670 | + struct dprc_endpoint *endpoint2, |
---|
| 671 | + int *state) |
---|
| 672 | +{ |
---|
| 673 | + struct dprc_cmd_get_connection *cmd_params; |
---|
| 674 | + struct dprc_rsp_get_connection *rsp_params; |
---|
| 675 | + struct fsl_mc_command cmd = { 0 }; |
---|
| 676 | + int err, i; |
---|
| 677 | + |
---|
| 678 | + /* prepare command */ |
---|
| 679 | + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION, |
---|
| 680 | + cmd_flags, |
---|
| 681 | + token); |
---|
| 682 | + cmd_params = (struct dprc_cmd_get_connection *)cmd.params; |
---|
| 683 | + cmd_params->ep1_id = cpu_to_le32(endpoint1->id); |
---|
| 684 | + cmd_params->ep1_interface_id = cpu_to_le16(endpoint1->if_id); |
---|
| 685 | + for (i = 0; i < 16; i++) |
---|
| 686 | + cmd_params->ep1_type[i] = endpoint1->type[i]; |
---|
| 687 | + |
---|
| 688 | + /* send command to mc */ |
---|
| 689 | + err = mc_send_command(mc_io, &cmd); |
---|
| 690 | + if (err) |
---|
| 691 | + return -ENOTCONN; |
---|
| 692 | + |
---|
| 693 | + /* retrieve response parameters */ |
---|
| 694 | + rsp_params = (struct dprc_rsp_get_connection *)cmd.params; |
---|
| 695 | + endpoint2->id = le32_to_cpu(rsp_params->ep2_id); |
---|
| 696 | + endpoint2->if_id = le16_to_cpu(rsp_params->ep2_interface_id); |
---|
| 697 | + *state = le32_to_cpu(rsp_params->state); |
---|
| 698 | + for (i = 0; i < 16; i++) |
---|
| 699 | + endpoint2->type[i] = rsp_params->ep2_type[i]; |
---|
| 700 | + |
---|
| 701 | + return 0; |
---|
| 702 | +} |
---|