Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'scmi-updates-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers

Arm SCMI updates for v6.16

1. Quirk framework to handle buggy firmware

With SCMI gaining broader adoption across arm64 platforms, it's
increasingly important to address how we consistently manage out-of-spec
SCMI firmware already deployed in the field. This change introduces a
lightweight quirk framework built around static_keys, enabling developers to:
- Define quirks and their match criteria, which can include:
o A list of compatibles ({ comp, comp2, NULL })
o Vendor ID / Sub-Vendor ID
o Firmware implementation version ranges ([Min_Vers, Max_Vers])

Matching proceeds from the most specific (longest match) to the least
specific. NULL entries are treated as wildcards (i.e., match any value).
This flexibility allows matching very specific combinations or just a
general compatible string.

The quirk code blocks/snippets implementing the workaround are placed near
their intended usage and guarded by a static_key that's tied to the quirk.
Once the SCMI core stack is initialized and retrieves platform info via the
base protocol, any matching quirks will have their associated static_keys
enabled.

2. Quirk for Qualcomm X1E platforms

On some Qualcomm X1E platforms, such as the Lenovo ThinkPad T14s, the
SCMI firmware fails to set the FastChannel support bit for PERF_LEVEL_GET,
yet it crashes when the driver attempts to fall back to standard messaging
which is clearly out-of-spec behavior.

To work around this, the new SCMI quirk framework is used to
unconditionally enable FC initialization for this firmware version.

In the future, once the fixed firmware version is identified, an upper
version bound can be added to the quirk match criteria. Alternatively,
matching can be further restricted using a SoC-specific compatible string
if always enabling FC proves problematic elsewhere.

3. Support for NXP i.MX LMM/CPU vendor protocol extensions

The i.MX95 System Manager (SM) implements Logical Machine Management (LMM)
and a CPU protocol to manage Logical Machines (LM) and CPUs (e.g., M7).

These changes integrate the vendor-specific protocol extensions
implementing the LMM and CPU protocols for the i.MX95, facilitating
standardized communication between the operating system and the platform's
firmware, which will be used by remoteproc drivers. The changes also
include the necessary device tree bindings.

4. Miscellaneous cleanups/changes

These mainly include polling support in SCMI raw mode. The cleanups
centralize error logging for SCMI device creation into a single helper
function, consolidate the device matching logic into a single function, and
ensure that devices must have a name for registration—removing support for
unnamed devices when matching drivers and devices for probing. Transport
devices are now excluded from bus matching, and the correct assignment of
the parent device for the arm-scmi platform device is ensured in the
transport drivers.

* tag 'scmi-updates-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
firmware: arm_scmi: quirk: Force perf level get fastchannel
firmware: arm_scmi: quirk: Fix CLOCK_DESCRIBE_RATES triplet
firmware: arm_scmi: Add common framework to handle firmware quirks
firmware: arm_scmi: Ensure that the message-id supports fastchannel
MAINTAINERS: add entry for i.MX SCMI extensions
firmware: imx: Add i.MX95 SCMI CPU driver
firmware: imx: Add i.MX95 SCMI LMM driver
firmware: arm_scmi: imx: Add i.MX95 CPU Protocol
firmware: arm_scmi: imx: Add i.MX95 LMM protocol
dt-bindings: firmware: Add i.MX95 SCMI LMM and CPU protocol
firmware: arm_scmi: imx: Add LMM and CPU documentation
firmware: arm_scmi: Add polling support to raw mode
firmware: arm_scmi: Exclude transport devices from bus matching
firmware: arm_scmi: Assign correct parent to arm-scmi platform device
firmware: arm_scmi: Refactor error logging from SCMI device creation to single helper
firmware: arm_scmi: Refactor device matching logic to eliminate duplication
firmware: arm_scmi: Ensure scmi_devices are always matched by name as well

Link: https://lore.kernel.org/r/20250507134713.49039-1-sudeep.holla@arm.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+2370 -99
+91
Documentation/ABI/testing/debugfs-scmi-raw
··· 31 31 (receiving an EOF at each message boundary). 32 32 Users: Debugging, any userspace test suite 33 33 34 + What: /sys/kernel/debug/scmi/<n>/raw/message_poll 35 + Date: June 2025 36 + KernelVersion: 6.16 37 + Contact: cristian.marussi@arm.com 38 + Description: SCMI Raw message injection/snooping facility using polling mode; 39 + write a complete SCMI command message (header included) in 40 + little-endian binary format to have it sent to the configured 41 + backend SCMI server for instance <n>, using polling mode on 42 + the reception path. (if transport is polling capable) 43 + Any subsequently received response can be read from this same 44 + entry if it arrived within the configured timeout. 45 + Each write to the entry causes one command request to be built 46 + and sent while the replies are read back one message at time 47 + (receiving an EOF at each message boundary). 48 + Users: Debugging, any userspace test suite 49 + 50 + What: /sys/kernel/debug/scmi/<n>/raw/message_poll_async 51 + Date: June 2025 52 + KernelVersion: 6.16 53 + Contact: cristian.marussi@arm.com 54 + Description: SCMI Raw asynchronous message injection/snooping facility using 55 + polling-mode; write a complete SCMI asynchronous command message 56 + (header included) in little-endian binary format to have it sent 57 + to the configured backend SCMI server for instance <n>, using 58 + polling-mode on the reception path of the immediate part of the 59 + asynchronous command. (if transport is polling capable) 60 + Any subsequently received response can be read from this same 61 + entry if it arrived within the configured timeout. 62 + Any additional delayed response received afterwards can be read 63 + from this same entry too if it arrived within the configured 64 + timeout. 65 + Each write to the entry causes one command request to be built 66 + and sent while the replies are read back one message at time 67 + (receiving an EOF at each message boundary). 68 + Users: Debugging, any userspace test suite 69 + 34 70 What: /sys/kernel/debug/scmi/<n>/raw/errors 35 71 Date: March 2023 36 72 KernelVersion: 6.3 ··· 134 98 in little-endian binary format to have it sent to the configured 135 99 backend SCMI server for instance <n> through the <m> transport 136 100 channel. 101 + Any subsequently received response can be read from this same 102 + entry if it arrived on channel <m> within the configured 103 + timeout. 104 + Any additional delayed response received afterwards can be read 105 + from this same entry too if it arrived within the configured 106 + timeout. 107 + Each write to the entry causes one command request to be built 108 + and sent while the replies are read back one message at time 109 + (receiving an EOF at each message boundary). 110 + Channel identifier <m> matches the SCMI protocol number which 111 + has been associated with this transport channel in the DT 112 + description, with base protocol number 0x10 being the default 113 + channel for this instance. 114 + Note that these per-channel entries rooted at <..>/channels 115 + exist only if the transport is configured to have more than 116 + one default channel. 117 + Users: Debugging, any userspace test suite 118 + 119 + 120 + What: /sys/kernel/debug/scmi/<n>/raw/channels/<m>/message_poll 121 + Date: June 2025 122 + KernelVersion: 6.16 123 + Contact: cristian.marussi@arm.com 124 + Description: SCMI Raw message injection/snooping facility using polling mode; 125 + write a complete SCMI command message (header included) in 126 + little-endian binary format to have it sent to the configured 127 + backend SCMI server for instance <n> through the <m> transport 128 + channel, using polling mode on the reception path. 129 + (if transport is polling capable) 130 + Any subsequently received response can be read from this same 131 + entry if it arrived on channel <m> within the configured 132 + timeout. 133 + Each write to the entry causes one command request to be built 134 + and sent while the replies are read back one message at time 135 + (receiving an EOF at each message boundary). 136 + Channel identifier <m> matches the SCMI protocol number which 137 + has been associated with this transport channel in the DT 138 + description, with base protocol number 0x10 being the default 139 + channel for this instance. 140 + Note that these per-channel entries rooted at <..>/channels 141 + exist only if the transport is configured to have more than 142 + one default channel. 143 + Users: Debugging, any userspace test suite 144 + 145 + What: /sys/kernel/debug/scmi/<n>/raw/channels/<m>/message_poll_async 146 + Date: June 2025 147 + KernelVersion: 6.16 148 + Contact: cristian.marussi@arm.com 149 + Description: SCMI Raw asynchronous message injection/snooping facility using 150 + polling-mode; write a complete SCMI asynchronous command message 151 + (header included) in little-endian binary format to have it sent 152 + to the configured backend SCMI server for instance <n> through 153 + the <m> transport channel, using polling mode on the reception 154 + path of the immediate part of the asynchronous command. 155 + (if transport is polling capable) 137 156 Any subsequently received response can be read from this same 138 157 entry if it arrived on channel <m> within the configured 139 158 timeout.
+23
Documentation/devicetree/bindings/firmware/nxp,imx95-scmi.yaml
··· 11 11 - Peng Fan <peng.fan@nxp.com> 12 12 13 13 properties: 14 + protocol@80: 15 + description: 16 + SCMI LMM protocol which is for boot, shutdown, and reset of other logical 17 + machines (LM). It is usually used to allow one LM to manage another used 18 + as an offload or accelerator engine. 19 + $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node' 20 + unevaluatedProperties: false 21 + 22 + properties: 23 + reg: 24 + const: 0x80 25 + 14 26 protocol@81: 15 27 $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node' 16 28 unevaluatedProperties: false ··· 30 18 properties: 31 19 reg: 32 20 const: 0x81 21 + 22 + protocol@82: 23 + description: 24 + SCMI CPU Protocol which allows an agent to start or stop a CPU. It is 25 + used to manage auxiliary CPUs in a LM. 26 + $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node' 27 + unevaluatedProperties: false 28 + 29 + properties: 30 + reg: 31 + const: 0x82 33 32 34 33 protocol@84: 35 34 $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node'
+9
MAINTAINERS
··· 23565 23565 F: include/trace/events/scmi.h 23566 23566 F: include/uapi/linux/virtio_scmi.h 23567 23567 23568 + SYSTEM CONTROL MANAGEMENT INTERFACE (SCMI) i.MX Extension Message Protocol drivers 23569 + M: Peng Fan <peng.fan@nxp.com> 23570 + L: arm-scmi@vger.kernel.org 23571 + L: imx@lists.linux.dev 23572 + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 23573 + S: Maintained 23574 + F: Documentation/devicetree/bindings/firmware/nxp,*scmi.yaml 23575 + F: drivers/firmware/arm_scmi/vendors/imx/ 23576 + 23568 23577 SYSTEM RESET/SHUTDOWN DRIVERS 23569 23578 M: Sebastian Reichel <sre@kernel.org> 23570 23579 L: linux-pm@vger.kernel.org
+13
drivers/firmware/arm_scmi/Kconfig
··· 69 69 such useful debug counters. This can be helpful for debugging and 70 70 SCMI monitoring. 71 71 72 + config ARM_SCMI_QUIRKS 73 + bool "Enable SCMI Quirks framework" 74 + depends on JUMP_LABEL || COMPILE_TEST 75 + default y 76 + help 77 + Enables support for SCMI Quirks framework to workaround SCMI platform 78 + firmware bugs on system already deployed in the wild. 79 + 80 + The framework allows the definition of platform-specific code quirks 81 + that will be associated and enabled only on the desired platforms 82 + depending on the SCMI firmware advertised versions and/or machine 83 + compatibles. 84 + 72 85 source "drivers/firmware/arm_scmi/transports/Kconfig" 73 86 source "drivers/firmware/arm_scmi/vendors/imx/Kconfig" 74 87
+1
drivers/firmware/arm_scmi/Makefile
··· 3 3 scmi-core-objs := $(scmi-bus-y) 4 4 5 5 scmi-driver-y = driver.o notify.o 6 + scmi-driver-$(CONFIG_ARM_SCMI_QUIRKS) += quirks.o 6 7 scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o 7 8 scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o 8 9 scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
+41 -36
drivers/firmware/arm_scmi/bus.c
··· 201 201 scmi_protocol_device_unrequest(entry); 202 202 } 203 203 204 - static const struct scmi_device_id * 205 - scmi_dev_match_id(struct scmi_device *scmi_dev, const struct scmi_driver *scmi_drv) 204 + static int scmi_dev_match_by_id_table(struct scmi_device *scmi_dev, 205 + const struct scmi_device_id *id_table) 206 206 { 207 - const struct scmi_device_id *id = scmi_drv->id_table; 207 + if (!id_table || !id_table->name) 208 + return 0; 208 209 209 - if (!id) 210 - return NULL; 210 + /* Always skip transport devices from matching */ 211 + for (; id_table->protocol_id && id_table->name; id_table++) 212 + if (id_table->protocol_id == scmi_dev->protocol_id && 213 + strncmp(scmi_dev->name, "__scmi_transport_device", 23) && 214 + !strcmp(id_table->name, scmi_dev->name)) 215 + return 1; 216 + return 0; 217 + } 211 218 212 - for (; id->protocol_id; id++) 213 - if (id->protocol_id == scmi_dev->protocol_id) { 214 - if (!id->name) 215 - return id; 216 - else if (!strcmp(id->name, scmi_dev->name)) 217 - return id; 218 - } 219 - 220 - return NULL; 219 + static int scmi_dev_match_id(struct scmi_device *scmi_dev, 220 + const struct scmi_driver *scmi_drv) 221 + { 222 + return scmi_dev_match_by_id_table(scmi_dev, scmi_drv->id_table); 221 223 } 222 224 223 225 static int scmi_dev_match(struct device *dev, const struct device_driver *drv) 224 226 { 225 227 const struct scmi_driver *scmi_drv = to_scmi_driver(drv); 226 228 struct scmi_device *scmi_dev = to_scmi_dev(dev); 227 - const struct scmi_device_id *id; 228 229 229 - id = scmi_dev_match_id(scmi_dev, scmi_drv); 230 - if (id) 231 - return 1; 232 - 233 - return 0; 230 + return scmi_dev_match_id(scmi_dev, scmi_drv); 234 231 } 235 232 236 233 static int scmi_match_by_id_table(struct device *dev, const void *data) 237 234 { 238 - struct scmi_device *sdev = to_scmi_dev(dev); 235 + struct scmi_device *scmi_dev = to_scmi_dev(dev); 239 236 const struct scmi_device_id *id_table = data; 240 237 241 - return sdev->protocol_id == id_table->protocol_id && 242 - (id_table->name && !strcmp(sdev->name, id_table->name)); 238 + return scmi_dev_match_by_id_table(scmi_dev, id_table); 243 239 } 244 240 245 241 static struct scmi_device *scmi_child_dev_find(struct device *parent, 246 242 int prot_id, const char *name) 247 243 { 248 - struct scmi_device_id id_table; 244 + struct scmi_device_id id_table[2] = { 0 }; 249 245 struct device *dev; 250 246 251 - id_table.protocol_id = prot_id; 252 - id_table.name = name; 247 + id_table[0].protocol_id = prot_id; 248 + id_table[0].name = name; 253 249 254 250 dev = device_find_child(parent, &id_table, scmi_match_by_id_table); 255 251 if (!dev) ··· 456 460 return NULL; 457 461 } 458 462 463 + static struct scmi_device * 464 + _scmi_device_create(struct device_node *np, struct device *parent, 465 + int protocol, const char *name) 466 + { 467 + struct scmi_device *sdev; 468 + 469 + sdev = __scmi_device_create(np, parent, protocol, name); 470 + if (!sdev) 471 + pr_err("(%s) Failed to create device for protocol 0x%x (%s)\n", 472 + of_node_full_name(parent->of_node), protocol, name); 473 + 474 + return sdev; 475 + } 476 + 459 477 /** 460 478 * scmi_device_create - A method to create one or more SCMI devices 461 479 * ··· 502 492 struct scmi_device *scmi_dev = NULL; 503 493 504 494 if (name) 505 - return __scmi_device_create(np, parent, protocol, name); 495 + return _scmi_device_create(np, parent, protocol, name); 506 496 507 497 mutex_lock(&scmi_requested_devices_mtx); 508 498 phead = idr_find(&scmi_requested_devices, protocol); ··· 516 506 list_for_each_entry(rdev, phead, node) { 517 507 struct scmi_device *sdev; 518 508 519 - sdev = __scmi_device_create(np, parent, 520 - rdev->id_table->protocol_id, 521 - rdev->id_table->name); 522 - /* Report errors and carry on... */ 509 + sdev = _scmi_device_create(np, parent, 510 + rdev->id_table->protocol_id, 511 + rdev->id_table->name); 523 512 if (sdev) 524 513 scmi_dev = sdev; 525 - else 526 - pr_err("(%s) Failed to create device for protocol 0x%x (%s)\n", 527 - of_node_full_name(parent->of_node), 528 - rdev->id_table->protocol_id, 529 - rdev->id_table->name); 530 514 } 515 + 531 516 mutex_unlock(&scmi_requested_devices_mtx); 532 517 533 518 return scmi_dev;
+20 -13
drivers/firmware/arm_scmi/clock.c
··· 11 11 12 12 #include "protocols.h" 13 13 #include "notify.h" 14 + #include "quirks.h" 14 15 15 16 /* Updated only after ALL the mandatory features for that version are merged */ 16 17 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 ··· 430 429 msg->rate_index = cpu_to_le32(desc_index); 431 430 } 432 431 432 + #define QUIRK_OUT_OF_SPEC_TRIPLET \ 433 + ({ \ 434 + /* \ 435 + * A known quirk: a triplet is returned but num_returned != 3 \ 436 + * Check for a safe payload size and fix. \ 437 + */ \ 438 + if (st->num_returned != 3 && st->num_remaining == 0 && \ 439 + st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) { \ 440 + st->num_returned = 3; \ 441 + st->num_remaining = 0; \ 442 + } else { \ 443 + dev_err(p->dev, \ 444 + "Cannot fix out-of-spec reply !\n"); \ 445 + return -EPROTO; \ 446 + } \ 447 + }) 448 + 433 449 static int 434 450 iter_clk_describe_update_state(struct scmi_iterator_state *st, 435 451 const void *response, void *priv) ··· 468 450 p->clk->name, st->num_returned, st->num_remaining, 469 451 st->rx_len); 470 452 471 - /* 472 - * A known quirk: a triplet is returned but num_returned != 3 473 - * Check for a safe payload size and fix. 474 - */ 475 - if (st->num_returned != 3 && st->num_remaining == 0 && 476 - st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) { 477 - st->num_returned = 3; 478 - st->num_remaining = 0; 479 - } else { 480 - dev_err(p->dev, 481 - "Cannot fix out-of-spec reply !\n"); 482 - return -EPROTO; 483 - } 453 + SCMI_QUIRK(clock_rates_triplet_out_of_spec, 454 + QUIRK_OUT_OF_SPEC_TRIPLET); 484 455 } 485 456 486 457 return 0;
+1
drivers/firmware/arm_scmi/common.h
··· 475 475 if (ret) \ 476 476 goto err; \ 477 477 \ 478 + spdev->dev.parent = dev; \ 478 479 ret = platform_device_add(spdev); \ 479 480 if (ret) \ 480 481 goto err; \
+74 -45
drivers/firmware/arm_scmi/driver.c
··· 11 11 * various power domain DVFS including the core/cluster, certain system 12 12 * clocks configuration, thermal sensors and many others. 13 13 * 14 - * Copyright (C) 2018-2024 ARM Ltd. 14 + * Copyright (C) 2018-2025 ARM Ltd. 15 15 */ 16 16 17 17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ··· 38 38 39 39 #include "common.h" 40 40 #include "notify.h" 41 + #include "quirks.h" 41 42 42 43 #include "raw_mode.h" 43 44 ··· 440 439 struct scmi_info *info, 441 440 int prot_id, const char *name) 442 441 { 443 - struct scmi_device *sdev; 444 - 445 442 mutex_lock(&info->devreq_mtx); 446 - sdev = scmi_device_create(np, info->dev, prot_id, name); 447 - if (name && !sdev) 448 - dev_err(info->dev, 449 - "failed to create device for protocol 0x%X (%s)\n", 450 - prot_id, name); 443 + scmi_device_create(np, info->dev, prot_id, name); 451 444 mutex_unlock(&info->devreq_mtx); 452 445 } 453 446 ··· 1185 1190 * RX path since it will be already queued at the end of the TX 1186 1191 * poll loop. 1187 1192 */ 1188 - if (!xfer->hdr.poll_completion) 1193 + if (!xfer->hdr.poll_completion || 1194 + xfer->hdr.type == MSG_TYPE_DELAYED_RESP) 1189 1195 scmi_raw_message_report(info->raw, xfer, 1190 1196 SCMI_RAW_REPLY_QUEUE, 1191 1197 cinfo->id); ··· 1731 1735 } 1732 1736 1733 1737 /** 1738 + * scmi_protocol_msg_check - Check protocol message attributes 1739 + * 1740 + * @ph: A reference to the protocol handle. 1741 + * @message_id: The ID of the message to check. 1742 + * @attributes: A parameter to optionally return the retrieved message 1743 + * attributes, in case of Success. 1744 + * 1745 + * An helper to check protocol message attributes for a specific protocol 1746 + * and message pair. 1747 + * 1748 + * Return: 0 on SUCCESS 1749 + */ 1750 + static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph, 1751 + u32 message_id, u32 *attributes) 1752 + { 1753 + int ret; 1754 + struct scmi_xfer *t; 1755 + 1756 + ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES, 1757 + sizeof(__le32), 0, &t); 1758 + if (ret) 1759 + return ret; 1760 + 1761 + put_unaligned_le32(message_id, t->tx.buf); 1762 + ret = do_xfer(ph, t); 1763 + if (!ret && attributes) 1764 + *attributes = get_unaligned_le32(t->rx.buf); 1765 + xfer_put(ph, t); 1766 + 1767 + return ret; 1768 + } 1769 + 1770 + /** 1734 1771 * struct scmi_iterator - Iterator descriptor 1735 1772 * @msg: A reference to the message TX buffer; filled by @prepare_message with 1736 1773 * a proper custom command payload for each multi-part command request. ··· 1895 1866 __le32 db_preserve_hmask; 1896 1867 }; 1897 1868 1869 + #define QUIRK_PERF_FC_FORCE \ 1870 + ({ \ 1871 + if (pi->proto->id == SCMI_PROTOCOL_PERF && \ 1872 + message_id == 0x8 /* PERF_LEVEL_GET */) \ 1873 + attributes |= BIT(0); \ 1874 + }) 1875 + 1898 1876 static void 1899 1877 scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph, 1900 1878 u8 describe_id, u32 message_id, u32 valid_size, ··· 1911 1875 int ret; 1912 1876 u32 flags; 1913 1877 u64 phys_addr; 1878 + u32 attributes; 1914 1879 u8 size; 1915 1880 void __iomem *addr; 1916 1881 struct scmi_xfer *t; ··· 1919 1882 struct scmi_msg_get_fc_info *info; 1920 1883 struct scmi_msg_resp_desc_fc *resp; 1921 1884 const struct scmi_protocol_instance *pi = ph_to_pi(ph); 1885 + 1886 + /* Check if the MSG_ID supports fastchannel */ 1887 + ret = scmi_protocol_msg_check(ph, message_id, &attributes); 1888 + SCMI_QUIRK(perf_level_get_fc_force, QUIRK_PERF_FC_FORCE); 1889 + if (ret || !MSG_SUPPORTS_FASTCHANNEL(attributes)) { 1890 + dev_dbg(ph->dev, 1891 + "Skip FC init for 0x%02X/%d domain:%d - ret:%d\n", 1892 + pi->proto->id, message_id, domain, ret); 1893 + return; 1894 + } 1922 1895 1923 1896 if (!p_addr) { 1924 1897 ret = -EINVAL; ··· 2045 1998 SCMI_PROTO_FC_RING_DB(32); 2046 1999 else /* db->width == 8 */ 2047 2000 SCMI_PROTO_FC_RING_DB(64); 2048 - } 2049 - 2050 - /** 2051 - * scmi_protocol_msg_check - Check protocol message attributes 2052 - * 2053 - * @ph: A reference to the protocol handle. 2054 - * @message_id: The ID of the message to check. 2055 - * @attributes: A parameter to optionally return the retrieved message 2056 - * attributes, in case of Success. 2057 - * 2058 - * An helper to check protocol message attributes for a specific protocol 2059 - * and message pair. 2060 - * 2061 - * Return: 0 on SUCCESS 2062 - */ 2063 - static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph, 2064 - u32 message_id, u32 *attributes) 2065 - { 2066 - int ret; 2067 - struct scmi_xfer *t; 2068 - 2069 - ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES, 2070 - sizeof(__le32), 0, &t); 2071 - if (ret) 2072 - return ret; 2073 - 2074 - put_unaligned_le32(message_id, t->tx.buf); 2075 - ret = do_xfer(ph, t); 2076 - if (!ret && attributes) 2077 - *attributes = get_unaligned_le32(t->rx.buf); 2078 - xfer_put(ph, t); 2079 - 2080 - return ret; 2081 2001 } 2082 2002 2083 2003 static const struct scmi_proto_helpers_ops helpers_ops = { ··· 2839 2825 struct scmi_info *info = bus_nb_to_scmi_info(nb); 2840 2826 struct scmi_device *sdev = to_scmi_dev(data); 2841 2827 2842 - /* Skip transport devices and devices of different SCMI instances */ 2843 - if (!strncmp(sdev->name, "__scmi_transport_device", 23) || 2844 - sdev->dev.parent != info->dev) 2828 + /* Skip devices of different SCMI instances */ 2829 + if (sdev->dev.parent != info->dev) 2845 2830 return NOTIFY_DONE; 2846 2831 2847 2832 switch (action) { ··· 3111 3098 return &trans->desc; 3112 3099 } 3113 3100 3101 + static void scmi_enable_matching_quirks(struct scmi_info *info) 3102 + { 3103 + struct scmi_revision_info *rev = &info->version; 3104 + 3105 + dev_dbg(info->dev, "Looking for quirks matching: %s/%s/0x%08X\n", 3106 + rev->vendor_id, rev->sub_vendor_id, rev->impl_ver); 3107 + 3108 + /* Enable applicable quirks */ 3109 + scmi_quirks_enable(info->dev, rev->vendor_id, 3110 + rev->sub_vendor_id, rev->impl_ver); 3111 + } 3112 + 3114 3113 static int scmi_probe(struct platform_device *pdev) 3115 3114 { 3116 3115 int ret; ··· 3243 3218 mutex_lock(&scmi_list_mutex); 3244 3219 list_add_tail(&info->node, &scmi_list); 3245 3220 mutex_unlock(&scmi_list_mutex); 3221 + 3222 + scmi_enable_matching_quirks(info); 3246 3223 3247 3224 for_each_available_child_of_node(np, child) { 3248 3225 u32 prot_id; ··· 3404 3377 3405 3378 static int __init scmi_driver_init(void) 3406 3379 { 3380 + scmi_quirks_initialize(); 3381 + 3407 3382 /* Bail out if no SCMI transport was configured */ 3408 3383 if (WARN_ON(!IS_ENABLED(CONFIG_ARM_SCMI_HAVE_TRANSPORT))) 3409 3384 return -EINVAL;
+2
drivers/firmware/arm_scmi/protocols.h
··· 31 31 32 32 #define SCMI_PROTOCOL_VENDOR_BASE 0x80 33 33 34 + #define MSG_SUPPORTS_FASTCHANNEL(x) ((x) & BIT(0)) 35 + 34 36 enum scmi_common_cmd { 35 37 PROTOCOL_VERSION = 0x0, 36 38 PROTOCOL_ATTRIBUTES = 0x1,
+322
drivers/firmware/arm_scmi/quirks.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * System Control and Management Interface (SCMI) Message Protocol Quirks 4 + * 5 + * Copyright (C) 2025 ARM Ltd. 6 + */ 7 + 8 + /** 9 + * DOC: Theory of operation 10 + * 11 + * A framework to define SCMI quirks and their activation conditions based on 12 + * existing static_keys kernel facilities. 13 + * 14 + * Quirks are named and their activation conditions defined using the macro 15 + * DEFINE_SCMI_QUIRK() in this file. 16 + * 17 + * After a quirk is defined, a corresponding entry must also be added to the 18 + * global @scmi_quirks_table in this file using __DECLARE_SCMI_QUIRK_ENTRY(). 19 + * 20 + * Additionally a corresponding quirk declaration must be added also to the 21 + * quirk.h file using DECLARE_SCMI_QUIRK(). 22 + * 23 + * The needed quirk code-snippet itself will be defined local to the SCMI code 24 + * that is meant to fix and will be associated to the previously defined quirk 25 + * and related activation conditions using the macro SCMI_QUIRK(). 26 + * 27 + * At runtime, during the SCMI stack probe sequence, once the SCMI Server had 28 + * advertised the running platform Vendor, SubVendor and Implementation Version 29 + * data, all the defined quirks matching the activation conditions will be 30 + * enabled. 31 + * 32 + * Example 33 + * 34 + * quirk.c 35 + * ------- 36 + * DEFINE_SCMI_QUIRK(fix_me, "vendor", "subvend", "0x12000-0x30000", 37 + * "someone,plat_A", "another,plat_b", "vend,sku"); 38 + * 39 + * static struct scmi_quirk *scmi_quirks_table[] = { 40 + * ... 41 + * __DECLARE_SCMI_QUIRK_ENTRY(fix_me), 42 + * NULL 43 + * }; 44 + * 45 + * quirk.h 46 + * ------- 47 + * DECLARE_SCMI_QUIRK(fix_me); 48 + * 49 + * <somewhere_in_the_scmi_stack.c> 50 + * ------------------------------ 51 + * 52 + * #define QUIRK_CODE_SNIPPET_FIX_ME() \ 53 + * ({ \ 54 + * if (p->condition) \ 55 + * a_ptr->calculated_val = 123; \ 56 + * }) 57 + * 58 + * 59 + * int some_function_to_fix(int param, struct something *p) 60 + * { 61 + * struct some_strut *a_ptr; 62 + * 63 + * a_ptr = some_load_func(p); 64 + * SCMI_QUIRK(fix_me, QUIRK_CODE_SNIPPET_FIX_ME); 65 + * some_more_func(a_ptr); 66 + * ... 67 + * 68 + * return 0; 69 + * } 70 + * 71 + */ 72 + 73 + #include <linux/ctype.h> 74 + #include <linux/device.h> 75 + #include <linux/export.h> 76 + #include <linux/hashtable.h> 77 + #include <linux/kstrtox.h> 78 + #include <linux/of.h> 79 + #include <linux/slab.h> 80 + #include <linux/static_key.h> 81 + #include <linux/string.h> 82 + #include <linux/stringhash.h> 83 + #include <linux/types.h> 84 + 85 + #include "quirks.h" 86 + 87 + #define SCMI_QUIRKS_HT_SZ 4 88 + 89 + struct scmi_quirk { 90 + bool enabled; 91 + const char *name; 92 + char *vendor; 93 + char *sub_vendor_id; 94 + char *impl_ver_range; 95 + u32 start_range; 96 + u32 end_range; 97 + struct static_key_false *key; 98 + struct hlist_node hash; 99 + unsigned int hkey; 100 + const char *const compats[]; 101 + }; 102 + 103 + #define __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ...) \ 104 + static struct scmi_quirk scmi_quirk_entry_ ## _qn = { \ 105 + .name = __stringify(quirk_ ## _qn), \ 106 + .vendor = _ven, \ 107 + .sub_vendor_id = _sub, \ 108 + .impl_ver_range = _impl, \ 109 + .key = &(scmi_quirk_ ## _qn), \ 110 + .compats = { __VA_ARGS__ __VA_OPT__(,) NULL }, \ 111 + } 112 + 113 + #define __DECLARE_SCMI_QUIRK_ENTRY(_qn) (&(scmi_quirk_entry_ ## _qn)) 114 + 115 + /* 116 + * Define a quirk by name and provide the matching tokens where: 117 + * 118 + * _qn: A string which will be used to build the quirk and the global 119 + * static_key names. 120 + * _ven : SCMI Vendor ID string match, NULL means any. 121 + * _sub : SCMI SubVendor ID string match, NULL means any. 122 + * _impl : SCMI Implementation Version string match, NULL means any. 123 + * This string can be used to express version ranges which will be 124 + * interpreted as follows: 125 + * 126 + * NULL [0, 0xFFFFFFFF] 127 + * "X" [X, X] 128 + * "X-" [X, 0xFFFFFFFF] 129 + * "-X" [0, X] 130 + * "X-Y" [X, Y] 131 + * 132 + * with X <= Y and <v> in [X, Y] meaning X <= <v> <= Y 133 + * 134 + * ... : An optional variadic macros argument used to provide a comma-separated 135 + * list of compatible strings matches; when no variadic argument is 136 + * provided, ANY compatible will match this quirk. 137 + * 138 + * This implicitly define also a properly named global static-key that 139 + * will be used to dynamically enable the quirk at initialization time. 140 + * 141 + * Note that it is possible to associate multiple quirks to the same 142 + * matching pattern, if your firmware quality is really astounding :P 143 + * 144 + * Example: 145 + * 146 + * Compatibles list NOT provided, so ANY compatible will match: 147 + * 148 + * DEFINE_SCMI_QUIRK(my_new_issue, "Vend", "SVend", "0x12000-0x30000"); 149 + * 150 + * 151 + * A few compatibles provided to match against: 152 + * 153 + * DEFINE_SCMI_QUIRK(my_new_issue, "Vend", "SVend", "0x12000-0x30000", 154 + * "xvend,plat_a", "xvend,plat_b", "xvend,sku_name"); 155 + */ 156 + #define DEFINE_SCMI_QUIRK(_qn, _ven, _sub, _impl, ...) \ 157 + DEFINE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn); \ 158 + __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ##__VA_ARGS__) 159 + 160 + /* 161 + * Same as DEFINE_SCMI_QUIRK but EXPORTED: this is meant to address quirks 162 + * that possibly reside in code that is included in loadable kernel modules 163 + * that needs to be able to access the global static keys at runtime to 164 + * determine if enabled or not. (see SCMI_QUIRK to understand usage) 165 + */ 166 + #define DEFINE_SCMI_QUIRK_EXPORTED(_qn, _ven, _sub, _impl, ...) \ 167 + DEFINE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn); \ 168 + EXPORT_SYMBOL_GPL(scmi_quirk_ ## _qn); \ 169 + __DEFINE_SCMI_QUIRK_ENTRY(_qn, _ven, _sub, _impl, ##__VA_ARGS__) 170 + 171 + /* Global Quirks Definitions */ 172 + DEFINE_SCMI_QUIRK(clock_rates_triplet_out_of_spec, NULL, NULL, NULL); 173 + DEFINE_SCMI_QUIRK(perf_level_get_fc_force, "Qualcomm", NULL, "0x20000-"); 174 + 175 + /* 176 + * Quirks Pointers Array 177 + * 178 + * This is filled at compile-time with the list of pointers to all the currently 179 + * defined quirks descriptors. 180 + */ 181 + static struct scmi_quirk *scmi_quirks_table[] = { 182 + __DECLARE_SCMI_QUIRK_ENTRY(clock_rates_triplet_out_of_spec), 183 + __DECLARE_SCMI_QUIRK_ENTRY(perf_level_get_fc_force), 184 + NULL 185 + }; 186 + 187 + /* 188 + * Quirks HashTable 189 + * 190 + * A run-time populated hashtable containing all the defined quirks descriptors 191 + * hashed by matching pattern. 192 + */ 193 + static DEFINE_READ_MOSTLY_HASHTABLE(scmi_quirks_ht, SCMI_QUIRKS_HT_SZ); 194 + 195 + static unsigned int scmi_quirk_signature(const char *vend, const char *sub_vend) 196 + { 197 + char *signature, *p; 198 + unsigned int hash32; 199 + unsigned long hash = 0; 200 + 201 + /* vendor_id/sub_vendor_id guaranteed <= SCMI_SHORT_NAME_MAX_SIZE */ 202 + signature = kasprintf(GFP_KERNEL, "|%s|%s|", vend ?: "", sub_vend ?: ""); 203 + if (!signature) 204 + return 0; 205 + 206 + pr_debug("SCMI Quirk Signature >>>%s<<<\n", signature); 207 + 208 + p = signature; 209 + while (*p) 210 + hash = partial_name_hash(tolower(*p++), hash); 211 + hash32 = end_name_hash(hash); 212 + 213 + kfree(signature); 214 + 215 + return hash32; 216 + } 217 + 218 + static int scmi_quirk_range_parse(struct scmi_quirk *quirk) 219 + { 220 + const char *last, *first = quirk->impl_ver_range; 221 + size_t len; 222 + char *sep; 223 + int ret; 224 + 225 + quirk->start_range = 0; 226 + quirk->end_range = 0xFFFFFFFF; 227 + len = quirk->impl_ver_range ? strlen(quirk->impl_ver_range) : 0; 228 + if (!len) 229 + return 0; 230 + 231 + last = first + len - 1; 232 + sep = strchr(quirk->impl_ver_range, '-'); 233 + if (sep) 234 + *sep = '\0'; 235 + 236 + if (sep == first) /* -X */ 237 + ret = kstrtouint(first + 1, 0, &quirk->end_range); 238 + else /* X OR X- OR X-y */ 239 + ret = kstrtouint(first, 0, &quirk->start_range); 240 + if (ret) 241 + return ret; 242 + 243 + if (!sep) 244 + quirk->end_range = quirk->start_range; 245 + else if (sep != last) /* x-Y */ 246 + ret = kstrtouint(sep + 1, 0, &quirk->end_range); 247 + 248 + if (quirk->start_range > quirk->end_range) 249 + return -EINVAL; 250 + 251 + return ret; 252 + } 253 + 254 + void scmi_quirks_initialize(void) 255 + { 256 + struct scmi_quirk *quirk; 257 + int i; 258 + 259 + for (i = 0, quirk = scmi_quirks_table[0]; quirk; 260 + i++, quirk = scmi_quirks_table[i]) { 261 + int ret; 262 + 263 + ret = scmi_quirk_range_parse(quirk); 264 + if (ret) { 265 + pr_err("SCMI skip QUIRK [%s] - BAD RANGE - |%s|\n", 266 + quirk->name, quirk->impl_ver_range); 267 + continue; 268 + } 269 + quirk->hkey = scmi_quirk_signature(quirk->vendor, 270 + quirk->sub_vendor_id); 271 + 272 + hash_add(scmi_quirks_ht, &quirk->hash, quirk->hkey); 273 + 274 + pr_debug("Registered SCMI QUIRK [%s] -- %p - Key [0x%08X] - %s/%s/[0x%08X-0x%08X]\n", 275 + quirk->name, quirk, quirk->hkey, 276 + quirk->vendor, quirk->sub_vendor_id, 277 + quirk->start_range, quirk->end_range); 278 + } 279 + 280 + pr_debug("SCMI Quirks initialized\n"); 281 + } 282 + 283 + void scmi_quirks_enable(struct device *dev, const char *vend, 284 + const char *subv, const u32 impl) 285 + { 286 + for (int i = 3; i >= 0; i--) { 287 + struct scmi_quirk *quirk; 288 + unsigned int hkey; 289 + 290 + hkey = scmi_quirk_signature(i > 1 ? vend : NULL, 291 + i > 2 ? subv : NULL); 292 + 293 + /* 294 + * Note that there could be multiple matches so we 295 + * will enable multiple quirk part of a hash collision 296 + * domain...BUT we cannot assume that ALL quirks on the 297 + * same collision domain are a full match. 298 + */ 299 + hash_for_each_possible(scmi_quirks_ht, quirk, hash, hkey) { 300 + if (quirk->enabled || quirk->hkey != hkey || 301 + impl < quirk->start_range || 302 + impl > quirk->end_range) 303 + continue; 304 + 305 + if (quirk->compats[0] && 306 + !of_machine_compatible_match(quirk->compats)) 307 + continue; 308 + 309 + dev_info(dev, "Enabling SCMI Quirk [%s]\n", 310 + quirk->name); 311 + 312 + dev_dbg(dev, 313 + "Quirk matched on: %s/%s/%s/[0x%08X-0x%08X]\n", 314 + quirk->compats[0], quirk->vendor, 315 + quirk->sub_vendor_id, 316 + quirk->start_range, quirk->end_range); 317 + 318 + static_branch_enable(quirk->key); 319 + quirk->enabled = true; 320 + } 321 + } 322 + }
+52
drivers/firmware/arm_scmi/quirks.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * System Control and Management Interface (SCMI) Message Protocol Quirks 4 + * 5 + * Copyright (C) 2025 ARM Ltd. 6 + */ 7 + #ifndef _SCMI_QUIRKS_H 8 + #define _SCMI_QUIRKS_H 9 + 10 + #include <linux/static_key.h> 11 + #include <linux/types.h> 12 + 13 + #ifdef CONFIG_ARM_SCMI_QUIRKS 14 + 15 + #define DECLARE_SCMI_QUIRK(_qn) \ 16 + DECLARE_STATIC_KEY_FALSE(scmi_quirk_ ## _qn) 17 + 18 + /* 19 + * A helper to associate the actual code snippet to use as a quirk 20 + * named as _qn. 21 + */ 22 + #define SCMI_QUIRK(_qn, _blk) \ 23 + do { \ 24 + if (static_branch_unlikely(&(scmi_quirk_ ## _qn))) \ 25 + (_blk); \ 26 + } while (0) 27 + 28 + void scmi_quirks_initialize(void); 29 + void scmi_quirks_enable(struct device *dev, const char *vend, 30 + const char *subv, const u32 impl); 31 + 32 + #else 33 + 34 + #define DECLARE_SCMI_QUIRK(_qn) 35 + /* Force quirks compilation even when SCMI Quirks are disabled */ 36 + #define SCMI_QUIRK(_qn, _blk) \ 37 + do { \ 38 + if (0) \ 39 + (_blk); \ 40 + } while (0) 41 + 42 + static inline void scmi_quirks_initialize(void) { } 43 + static inline void scmi_quirks_enable(struct device *dev, const char *vend, 44 + const char *sub_vend, const u32 impl) { } 45 + 46 + #endif /* CONFIG_ARM_SCMI_QUIRKS */ 47 + 48 + /* Quirk delarations */ 49 + DECLARE_SCMI_QUIRK(clock_rates_triplet_out_of_spec); 50 + DECLARE_SCMI_QUIRK(perf_level_get_fc_force); 51 + 52 + #endif /* _SCMI_QUIRKS_H */
+67 -5
drivers/firmware/arm_scmi/raw_mode.c
··· 671 671 * @len: Length of the message in @buf. 672 672 * @chan_id: The channel ID to use. 673 673 * @async: A flag stating if an asynchronous command is required. 674 + * @poll: A flag stating if a polling transmission is required. 674 675 * 675 676 * Return: 0 on Success 676 677 */ 677 678 static int scmi_raw_message_send(struct scmi_raw_mode_info *raw, 678 - void *buf, size_t len, u8 chan_id, bool async) 679 + void *buf, size_t len, u8 chan_id, 680 + bool async, bool poll) 679 681 { 680 682 int ret; 681 683 struct scmi_xfer *xfer; ··· 685 683 ret = scmi_xfer_raw_get_init(raw, buf, len, &xfer); 686 684 if (ret) 687 685 return ret; 686 + 687 + if (poll) { 688 + if (is_transport_polling_capable(raw->desc)) { 689 + xfer->hdr.poll_completion = true; 690 + } else { 691 + dev_err(raw->handle->dev, 692 + "Failed to send RAW message - Polling NOT supported\n"); 693 + return -EINVAL; 694 + } 695 + } 688 696 689 697 ret = scmi_do_xfer_raw_start(raw, xfer, chan_id, async); 690 698 if (ret) ··· 813 801 static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp, 814 802 const char __user *buf, 815 803 size_t count, loff_t *ppos, 816 - bool async) 804 + bool async, bool poll) 817 805 { 818 806 int ret; 819 807 struct scmi_dbg_raw_data *rd = filp->private_data; ··· 843 831 } 844 832 845 833 ret = scmi_raw_message_send(rd->raw, rd->tx.buf, rd->tx_size, 846 - rd->chan_id, async); 834 + rd->chan_id, async, poll); 847 835 848 836 /* Reset ppos for next message ... */ 849 837 rd->tx_size = 0; ··· 887 875 const char __user *buf, 888 876 size_t count, loff_t *ppos) 889 877 { 890 - return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, false); 878 + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, 879 + false, false); 891 880 } 892 881 893 882 static __poll_t scmi_dbg_raw_mode_message_poll(struct file *filp, ··· 977 964 const char __user *buf, 978 965 size_t count, loff_t *ppos) 979 966 { 980 - return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, true); 967 + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, 968 + true, false); 981 969 } 982 970 983 971 static const struct file_operations scmi_dbg_raw_mode_message_async_fops = { ··· 986 972 .release = scmi_dbg_raw_mode_release, 987 973 .read = scmi_dbg_raw_mode_message_read, 988 974 .write = scmi_dbg_raw_mode_message_async_write, 975 + .poll = scmi_dbg_raw_mode_message_poll, 976 + .owner = THIS_MODULE, 977 + }; 978 + 979 + static ssize_t scmi_dbg_raw_mode_message_poll_write(struct file *filp, 980 + const char __user *buf, 981 + size_t count, loff_t *ppos) 982 + { 983 + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, 984 + false, true); 985 + } 986 + 987 + static const struct file_operations scmi_dbg_raw_mode_message_poll_fops = { 988 + .open = scmi_dbg_raw_mode_open, 989 + .release = scmi_dbg_raw_mode_release, 990 + .read = scmi_dbg_raw_mode_message_read, 991 + .write = scmi_dbg_raw_mode_message_poll_write, 992 + .poll = scmi_dbg_raw_mode_message_poll, 993 + .owner = THIS_MODULE, 994 + }; 995 + 996 + static ssize_t scmi_dbg_raw_mode_message_poll_async_write(struct file *filp, 997 + const char __user *buf, 998 + size_t count, loff_t *ppos) 999 + { 1000 + return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, 1001 + true, true); 1002 + } 1003 + 1004 + static const struct file_operations scmi_dbg_raw_mode_message_poll_async_fops = { 1005 + .open = scmi_dbg_raw_mode_open, 1006 + .release = scmi_dbg_raw_mode_release, 1007 + .read = scmi_dbg_raw_mode_message_read, 1008 + .write = scmi_dbg_raw_mode_message_poll_async_write, 989 1009 .poll = scmi_dbg_raw_mode_message_poll, 990 1010 .owner = THIS_MODULE, 991 1011 }; ··· 1247 1199 debugfs_create_file("message_async", 0600, raw->dentry, raw, 1248 1200 &scmi_dbg_raw_mode_message_async_fops); 1249 1201 1202 + debugfs_create_file("message_poll", 0600, raw->dentry, raw, 1203 + &scmi_dbg_raw_mode_message_poll_fops); 1204 + 1205 + debugfs_create_file("message_poll_async", 0600, raw->dentry, raw, 1206 + &scmi_dbg_raw_mode_message_poll_async_fops); 1207 + 1250 1208 debugfs_create_file("notification", 0400, raw->dentry, raw, 1251 1209 &scmi_dbg_raw_mode_notification_fops); 1252 1210 ··· 1284 1230 debugfs_create_file_aux_num("message_async", 0600, chd, 1285 1231 raw, channels[i], 1286 1232 &scmi_dbg_raw_mode_message_async_fops); 1233 + 1234 + debugfs_create_file_aux_num("message_poll", 0600, chd, 1235 + raw, channels[i], 1236 + &scmi_dbg_raw_mode_message_poll_fops); 1237 + 1238 + debugfs_create_file_aux_num("message_poll_async", 0600, 1239 + chd, raw, channels[i], 1240 + &scmi_dbg_raw_mode_message_poll_async_fops); 1287 1241 } 1288 1242 } 1289 1243
+24
drivers/firmware/arm_scmi/vendors/imx/Kconfig
··· 12 12 To compile this driver as a module, choose M here: the 13 13 module will be called imx-sm-bbm. 14 14 15 + config IMX_SCMI_CPU_EXT 16 + tristate "i.MX SCMI CPU EXTENSION" 17 + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) 18 + depends on IMX_SCMI_CPU_DRV 19 + default y if ARCH_MXC 20 + help 21 + This enables i.MX System CPU Protocol to manage cpu 22 + start, stop and etc. 23 + 24 + To compile this driver as a module, choose M here: the 25 + module will be called imx-sm-cpu. 26 + 27 + config IMX_SCMI_LMM_EXT 28 + tristate "i.MX SCMI LMM EXTENSION" 29 + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) 30 + depends on IMX_SCMI_LMM_DRV 31 + default y if ARCH_MXC 32 + help 33 + This enables i.MX System Logical Machine Protocol to 34 + manage Logical Machines boot, shutdown and etc. 35 + 36 + To compile this driver as a module, choose M here: the 37 + module will be called imx-sm-lmm. 38 + 15 39 config IMX_SCMI_MISC_EXT 16 40 tristate "i.MX SCMI MISC EXTENSION" 17 41 depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+2
drivers/firmware/arm_scmi/vendors/imx/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 obj-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o 3 + obj-$(CONFIG_IMX_SCMI_CPU_EXT) += imx-sm-cpu.o 4 + obj-$(CONFIG_IMX_SCMI_LMM_EXT) += imx-sm-lmm.o 3 5 obj-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o
+276
drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * System control and Management Interface (SCMI) NXP CPU Protocol 4 + * 5 + * Copyright 2025 NXP 6 + */ 7 + 8 + #include <linux/bits.h> 9 + #include <linux/io.h> 10 + #include <linux/module.h> 11 + #include <linux/of.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/scmi_protocol.h> 14 + #include <linux/scmi_imx_protocol.h> 15 + 16 + #include "../../protocols.h" 17 + #include "../../notify.h" 18 + 19 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000 20 + 21 + enum scmi_imx_cpu_protocol_cmd { 22 + SCMI_IMX_CPU_ATTRIBUTES = 0x3, 23 + SCMI_IMX_CPU_START = 0x4, 24 + SCMI_IMX_CPU_STOP = 0x5, 25 + SCMI_IMX_CPU_RESET_VECTOR_SET = 0x6, 26 + SCMI_IMX_CPU_INFO_GET = 0xC, 27 + }; 28 + 29 + struct scmi_imx_cpu_info { 30 + u32 nr_cpu; 31 + }; 32 + 33 + #define SCMI_IMX_CPU_NR_CPU_MASK GENMASK(15, 0) 34 + struct scmi_msg_imx_cpu_protocol_attributes { 35 + __le32 attributes; 36 + }; 37 + 38 + struct scmi_msg_imx_cpu_attributes_out { 39 + __le32 attributes; 40 + #define CPU_MAX_NAME 16 41 + u8 name[CPU_MAX_NAME]; 42 + }; 43 + 44 + struct scmi_imx_cpu_reset_vector_set_in { 45 + __le32 cpuid; 46 + #define CPU_VEC_FLAGS_RESUME BIT(31) 47 + #define CPU_VEC_FLAGS_START BIT(30) 48 + #define CPU_VEC_FLAGS_BOOT BIT(29) 49 + __le32 flags; 50 + __le32 resetvectorlow; 51 + __le32 resetvectorhigh; 52 + }; 53 + 54 + struct scmi_imx_cpu_info_get_out { 55 + #define CPU_RUN_MODE_START 0 56 + #define CPU_RUN_MODE_HOLD 1 57 + #define CPU_RUN_MODE_STOP 2 58 + #define CPU_RUN_MODE_SLEEP 3 59 + __le32 runmode; 60 + __le32 sleepmode; 61 + __le32 resetvectorlow; 62 + __le32 resetvectorhigh; 63 + }; 64 + 65 + static int scmi_imx_cpu_validate_cpuid(const struct scmi_protocol_handle *ph, 66 + u32 cpuid) 67 + { 68 + struct scmi_imx_cpu_info *info = ph->get_priv(ph); 69 + 70 + if (cpuid >= info->nr_cpu) 71 + return -EINVAL; 72 + 73 + return 0; 74 + } 75 + 76 + static int scmi_imx_cpu_start(const struct scmi_protocol_handle *ph, 77 + u32 cpuid, bool start) 78 + { 79 + struct scmi_xfer *t; 80 + u8 msg_id; 81 + int ret; 82 + 83 + ret = scmi_imx_cpu_validate_cpuid(ph, cpuid); 84 + if (ret) 85 + return ret; 86 + 87 + if (start) 88 + msg_id = SCMI_IMX_CPU_START; 89 + else 90 + msg_id = SCMI_IMX_CPU_STOP; 91 + 92 + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), 0, &t); 93 + if (ret) 94 + return ret; 95 + 96 + put_unaligned_le32(cpuid, t->tx.buf); 97 + ret = ph->xops->do_xfer(ph, t); 98 + 99 + ph->xops->xfer_put(ph, t); 100 + 101 + return ret; 102 + } 103 + 104 + static int scmi_imx_cpu_reset_vector_set(const struct scmi_protocol_handle *ph, 105 + u32 cpuid, u64 vector, bool start, 106 + bool boot, bool resume) 107 + { 108 + struct scmi_imx_cpu_reset_vector_set_in *in; 109 + struct scmi_xfer *t; 110 + int ret; 111 + 112 + ret = scmi_imx_cpu_validate_cpuid(ph, cpuid); 113 + if (ret) 114 + return ret; 115 + 116 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_RESET_VECTOR_SET, sizeof(*in), 117 + 0, &t); 118 + if (ret) 119 + return ret; 120 + 121 + in = t->tx.buf; 122 + in->cpuid = cpu_to_le32(cpuid); 123 + in->flags = cpu_to_le32(0); 124 + if (start) 125 + in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_START); 126 + if (boot) 127 + in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_BOOT); 128 + if (resume) 129 + in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_RESUME); 130 + in->resetvectorlow = cpu_to_le32(lower_32_bits(vector)); 131 + in->resetvectorhigh = cpu_to_le32(upper_32_bits(vector)); 132 + ret = ph->xops->do_xfer(ph, t); 133 + 134 + ph->xops->xfer_put(ph, t); 135 + 136 + return ret; 137 + } 138 + 139 + static int scmi_imx_cpu_started(const struct scmi_protocol_handle *ph, u32 cpuid, 140 + bool *started) 141 + { 142 + struct scmi_imx_cpu_info_get_out *out; 143 + struct scmi_xfer *t; 144 + u32 mode; 145 + int ret; 146 + 147 + if (!started) 148 + return -EINVAL; 149 + 150 + *started = false; 151 + ret = scmi_imx_cpu_validate_cpuid(ph, cpuid); 152 + if (ret) 153 + return ret; 154 + 155 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_INFO_GET, sizeof(u32), 156 + 0, &t); 157 + if (ret) 158 + return ret; 159 + 160 + put_unaligned_le32(cpuid, t->tx.buf); 161 + ret = ph->xops->do_xfer(ph, t); 162 + if (!ret) { 163 + out = t->rx.buf; 164 + mode = le32_to_cpu(out->runmode); 165 + if (mode == CPU_RUN_MODE_START || mode == CPU_RUN_MODE_SLEEP) 166 + *started = true; 167 + } 168 + 169 + ph->xops->xfer_put(ph, t); 170 + 171 + return ret; 172 + } 173 + 174 + static const struct scmi_imx_cpu_proto_ops scmi_imx_cpu_proto_ops = { 175 + .cpu_reset_vector_set = scmi_imx_cpu_reset_vector_set, 176 + .cpu_start = scmi_imx_cpu_start, 177 + .cpu_started = scmi_imx_cpu_started, 178 + }; 179 + 180 + static int scmi_imx_cpu_protocol_attributes_get(const struct scmi_protocol_handle *ph, 181 + struct scmi_imx_cpu_info *info) 182 + { 183 + struct scmi_msg_imx_cpu_protocol_attributes *attr; 184 + struct scmi_xfer *t; 185 + int ret; 186 + 187 + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, 188 + sizeof(*attr), &t); 189 + if (ret) 190 + return ret; 191 + 192 + attr = t->rx.buf; 193 + 194 + ret = ph->xops->do_xfer(ph, t); 195 + if (!ret) { 196 + info->nr_cpu = le32_get_bits(attr->attributes, SCMI_IMX_CPU_NR_CPU_MASK); 197 + dev_info(ph->dev, "i.MX SM CPU: %d cpus\n", 198 + info->nr_cpu); 199 + } 200 + 201 + ph->xops->xfer_put(ph, t); 202 + 203 + return ret; 204 + } 205 + 206 + static int scmi_imx_cpu_attributes_get(const struct scmi_protocol_handle *ph, 207 + u32 cpuid) 208 + { 209 + struct scmi_msg_imx_cpu_attributes_out *out; 210 + char name[SCMI_SHORT_NAME_MAX_SIZE] = {'\0'}; 211 + struct scmi_xfer *t; 212 + int ret; 213 + 214 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_ATTRIBUTES, sizeof(u32), 0, &t); 215 + if (ret) 216 + return ret; 217 + 218 + put_unaligned_le32(cpuid, t->tx.buf); 219 + ret = ph->xops->do_xfer(ph, t); 220 + if (!ret) { 221 + out = t->rx.buf; 222 + strscpy(name, out->name, SCMI_SHORT_NAME_MAX_SIZE); 223 + dev_info(ph->dev, "i.MX CPU: name: %s\n", name); 224 + } else { 225 + dev_err(ph->dev, "i.MX cpu: Failed to get info of cpu(%u)\n", cpuid); 226 + } 227 + 228 + ph->xops->xfer_put(ph, t); 229 + 230 + return ret; 231 + } 232 + 233 + static int scmi_imx_cpu_protocol_init(const struct scmi_protocol_handle *ph) 234 + { 235 + struct scmi_imx_cpu_info *info; 236 + u32 version; 237 + int ret, i; 238 + 239 + ret = ph->xops->version_get(ph, &version); 240 + if (ret) 241 + return ret; 242 + 243 + dev_info(ph->dev, "NXP SM CPU Protocol Version %d.%d\n", 244 + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 245 + 246 + info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL); 247 + if (!info) 248 + return -ENOMEM; 249 + 250 + ret = scmi_imx_cpu_protocol_attributes_get(ph, info); 251 + if (ret) 252 + return ret; 253 + 254 + for (i = 0; i < info->nr_cpu; i++) { 255 + ret = scmi_imx_cpu_attributes_get(ph, i); 256 + if (ret) 257 + return ret; 258 + } 259 + 260 + return ph->set_priv(ph, info, version); 261 + } 262 + 263 + static const struct scmi_protocol scmi_imx_cpu = { 264 + .id = SCMI_PROTOCOL_IMX_CPU, 265 + .owner = THIS_MODULE, 266 + .instance_init = &scmi_imx_cpu_protocol_init, 267 + .ops = &scmi_imx_cpu_proto_ops, 268 + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 269 + .vendor_id = SCMI_IMX_VENDOR, 270 + .sub_vendor_id = SCMI_IMX_SUBVENDOR, 271 + }; 272 + module_scmi_protocol(scmi_imx_cpu); 273 + 274 + MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_CPU) "-" SCMI_IMX_VENDOR); 275 + MODULE_DESCRIPTION("i.MX SCMI CPU driver"); 276 + MODULE_LICENSE("GPL");
+263
drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * System control and Management Interface (SCMI) NXP LMM Protocol 4 + * 5 + * Copyright 2025 NXP 6 + */ 7 + 8 + #include <linux/bits.h> 9 + #include <linux/io.h> 10 + #include <linux/module.h> 11 + #include <linux/of.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/scmi_protocol.h> 14 + #include <linux/scmi_imx_protocol.h> 15 + 16 + #include "../../protocols.h" 17 + #include "../../notify.h" 18 + 19 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000 20 + 21 + enum scmi_imx_lmm_protocol_cmd { 22 + SCMI_IMX_LMM_ATTRIBUTES = 0x3, 23 + SCMI_IMX_LMM_BOOT = 0x4, 24 + SCMI_IMX_LMM_RESET = 0x5, 25 + SCMI_IMX_LMM_SHUTDOWN = 0x6, 26 + SCMI_IMX_LMM_WAKE = 0x7, 27 + SCMI_IMX_LMM_SUSPEND = 0x8, 28 + SCMI_IMX_LMM_NOTIFY = 0x9, 29 + SCMI_IMX_LMM_RESET_REASON = 0xA, 30 + SCMI_IMX_LMM_POWER_ON = 0xB, 31 + SCMI_IMX_LMM_RESET_VECTOR_SET = 0xC, 32 + }; 33 + 34 + struct scmi_imx_lmm_priv { 35 + u32 nr_lmm; 36 + }; 37 + 38 + #define SCMI_IMX_LMM_NR_LM_MASK GENMASK(5, 0) 39 + #define SCMI_IMX_LMM_NR_MAX 16 40 + struct scmi_msg_imx_lmm_protocol_attributes { 41 + __le32 attributes; 42 + }; 43 + 44 + struct scmi_msg_imx_lmm_attributes_out { 45 + __le32 lmid; 46 + __le32 attributes; 47 + __le32 state; 48 + __le32 errstatus; 49 + u8 name[LMM_MAX_NAME]; 50 + }; 51 + 52 + struct scmi_imx_lmm_reset_vector_set_in { 53 + __le32 lmid; 54 + __le32 cpuid; 55 + __le32 flags; /* reserved for future extension */ 56 + __le32 resetvectorlow; 57 + __le32 resetvectorhigh; 58 + }; 59 + 60 + struct scmi_imx_lmm_shutdown_in { 61 + __le32 lmid; 62 + #define SCMI_IMX_LMM_SHUTDOWN_GRACEFUL BIT(0) 63 + __le32 flags; 64 + }; 65 + 66 + static int scmi_imx_lmm_validate_lmid(const struct scmi_protocol_handle *ph, u32 lmid) 67 + { 68 + struct scmi_imx_lmm_priv *priv = ph->get_priv(ph); 69 + 70 + if (lmid >= priv->nr_lmm) 71 + return -EINVAL; 72 + 73 + return 0; 74 + } 75 + 76 + static int scmi_imx_lmm_attributes(const struct scmi_protocol_handle *ph, 77 + u32 lmid, struct scmi_imx_lmm_info *info) 78 + { 79 + struct scmi_msg_imx_lmm_attributes_out *out; 80 + struct scmi_xfer *t; 81 + int ret; 82 + 83 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_ATTRIBUTES, sizeof(u32), 0, &t); 84 + if (ret) 85 + return ret; 86 + 87 + put_unaligned_le32(lmid, t->tx.buf); 88 + ret = ph->xops->do_xfer(ph, t); 89 + if (!ret) { 90 + out = t->rx.buf; 91 + info->lmid = le32_to_cpu(out->lmid); 92 + info->state = le32_to_cpu(out->state); 93 + info->errstatus = le32_to_cpu(out->errstatus); 94 + strscpy(info->name, out->name); 95 + dev_dbg(ph->dev, "i.MX LMM: Logical Machine(%d), name: %s\n", 96 + info->lmid, info->name); 97 + } else { 98 + dev_err(ph->dev, "i.MX LMM: Failed to get info of Logical Machine(%u)\n", lmid); 99 + } 100 + 101 + ph->xops->xfer_put(ph, t); 102 + 103 + return ret; 104 + } 105 + 106 + static int 107 + scmi_imx_lmm_power_boot(const struct scmi_protocol_handle *ph, u32 lmid, bool boot) 108 + { 109 + struct scmi_xfer *t; 110 + u8 msg_id; 111 + int ret; 112 + 113 + ret = scmi_imx_lmm_validate_lmid(ph, lmid); 114 + if (ret) 115 + return ret; 116 + 117 + if (boot) 118 + msg_id = SCMI_IMX_LMM_BOOT; 119 + else 120 + msg_id = SCMI_IMX_LMM_POWER_ON; 121 + 122 + ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), 0, &t); 123 + if (ret) 124 + return ret; 125 + 126 + put_unaligned_le32(lmid, t->tx.buf); 127 + ret = ph->xops->do_xfer(ph, t); 128 + 129 + ph->xops->xfer_put(ph, t); 130 + 131 + return ret; 132 + } 133 + 134 + static int scmi_imx_lmm_reset_vector_set(const struct scmi_protocol_handle *ph, 135 + u32 lmid, u32 cpuid, u32 flags, u64 vector) 136 + { 137 + struct scmi_imx_lmm_reset_vector_set_in *in; 138 + struct scmi_xfer *t; 139 + int ret; 140 + 141 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_RESET_VECTOR_SET, sizeof(*in), 142 + 0, &t); 143 + if (ret) 144 + return ret; 145 + 146 + in = t->tx.buf; 147 + in->lmid = cpu_to_le32(lmid); 148 + in->cpuid = cpu_to_le32(cpuid); 149 + in->flags = cpu_to_le32(0); 150 + in->resetvectorlow = cpu_to_le32(lower_32_bits(vector)); 151 + in->resetvectorhigh = cpu_to_le32(upper_32_bits(vector)); 152 + ret = ph->xops->do_xfer(ph, t); 153 + 154 + ph->xops->xfer_put(ph, t); 155 + 156 + return ret; 157 + } 158 + 159 + static int scmi_imx_lmm_shutdown(const struct scmi_protocol_handle *ph, u32 lmid, 160 + u32 flags) 161 + { 162 + struct scmi_imx_lmm_shutdown_in *in; 163 + struct scmi_xfer *t; 164 + int ret; 165 + 166 + ret = scmi_imx_lmm_validate_lmid(ph, lmid); 167 + if (ret) 168 + return ret; 169 + 170 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_SHUTDOWN, sizeof(*in), 171 + 0, &t); 172 + if (ret) 173 + return ret; 174 + 175 + in = t->tx.buf; 176 + in->lmid = cpu_to_le32(lmid); 177 + if (flags & SCMI_IMX_LMM_SHUTDOWN_GRACEFUL) 178 + in->flags = cpu_to_le32(SCMI_IMX_LMM_SHUTDOWN_GRACEFUL); 179 + else 180 + in->flags = cpu_to_le32(0); 181 + ret = ph->xops->do_xfer(ph, t); 182 + 183 + ph->xops->xfer_put(ph, t); 184 + 185 + return ret; 186 + } 187 + 188 + static const struct scmi_imx_lmm_proto_ops scmi_imx_lmm_proto_ops = { 189 + .lmm_power_boot = scmi_imx_lmm_power_boot, 190 + .lmm_info = scmi_imx_lmm_attributes, 191 + .lmm_reset_vector_set = scmi_imx_lmm_reset_vector_set, 192 + .lmm_shutdown = scmi_imx_lmm_shutdown, 193 + }; 194 + 195 + static int scmi_imx_lmm_protocol_attributes_get(const struct scmi_protocol_handle *ph, 196 + struct scmi_imx_lmm_priv *priv) 197 + { 198 + struct scmi_msg_imx_lmm_protocol_attributes *attr; 199 + struct scmi_xfer *t; 200 + int ret; 201 + 202 + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, 203 + sizeof(*attr), &t); 204 + if (ret) 205 + return ret; 206 + 207 + attr = t->rx.buf; 208 + 209 + ret = ph->xops->do_xfer(ph, t); 210 + if (!ret) { 211 + priv->nr_lmm = le32_get_bits(attr->attributes, SCMI_IMX_LMM_NR_LM_MASK); 212 + if (priv->nr_lmm > SCMI_IMX_LMM_NR_MAX) { 213 + dev_err(ph->dev, "i.MX LMM: %d:Exceed max supported Logical Machines\n", 214 + priv->nr_lmm); 215 + ret = -EINVAL; 216 + } else { 217 + dev_info(ph->dev, "i.MX LMM: %d Logical Machines\n", priv->nr_lmm); 218 + } 219 + } 220 + 221 + ph->xops->xfer_put(ph, t); 222 + 223 + return ret; 224 + } 225 + 226 + static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph) 227 + { 228 + struct scmi_imx_lmm_priv *info; 229 + u32 version; 230 + int ret; 231 + 232 + ret = ph->xops->version_get(ph, &version); 233 + if (ret) 234 + return ret; 235 + 236 + dev_info(ph->dev, "NXP SM LMM Version %d.%d\n", 237 + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 238 + 239 + info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL); 240 + if (!info) 241 + return -ENOMEM; 242 + 243 + ret = scmi_imx_lmm_protocol_attributes_get(ph, info); 244 + if (ret) 245 + return ret; 246 + 247 + return ph->set_priv(ph, info, version); 248 + } 249 + 250 + static const struct scmi_protocol scmi_imx_lmm = { 251 + .id = SCMI_PROTOCOL_IMX_LMM, 252 + .owner = THIS_MODULE, 253 + .instance_init = &scmi_imx_lmm_protocol_init, 254 + .ops = &scmi_imx_lmm_proto_ops, 255 + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 256 + .vendor_id = SCMI_IMX_VENDOR, 257 + .sub_vendor_id = SCMI_IMX_SUBVENDOR, 258 + }; 259 + module_scmi_protocol(scmi_imx_lmm); 260 + 261 + MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_LMM) "-" SCMI_IMX_VENDOR); 262 + MODULE_DESCRIPTION("i.MX SCMI LMM driver"); 263 + MODULE_LICENSE("GPL");
+828
drivers/firmware/arm_scmi/vendors/imx/imx95.rst
··· 32 32 The SM implements an interface compliant with the Arm SCMI Specification 33 33 with additional vendor specific extensions. 34 34 35 + System Control and Management Logical Machine Management Vendor Protocol 36 + ======================================================================== 37 + 38 + The SM adds the concept of logical machines (LMs). These are analogous to 39 + VMs and each has its own instance of SCMI. All normal SCMI calls only apply 40 + the LM running the calling agent. That includes boot, shutdown, reset, 41 + suspend, wake, etc. If a caller makes the SCMI base call to get a list 42 + of agents, it will only get those on that LM. Each LM is completely isolated 43 + from the others. This is mandatory for these to operate independently. 44 + 45 + This protocol is intended to support boot, shutdown, and reset of other logical 46 + machines (LM). It is usually used to allow one LM(e.g. OSPM) to manage 47 + another LM which is usually an offload or accelerator engine. Notifications 48 + from this protocol can also be used to manage a communication link to another 49 + LM. The LMM protocol provides commands to: 50 + 51 + - Describe the protocol version. 52 + - Discover implementation attributes. 53 + - Discover all the LMs defined in the system. 54 + - Boot a target LM. 55 + - Shutdown a target LM (gracefully or forcibly). 56 + - Reset a target LM (gracefully or forcibly). 57 + - Wake a target LM from suspend. 58 + - Suspend a target LM (gracefully). 59 + - Read boot/shutdown/reset information for a target LM. 60 + - Get notifications when a target LM boots or shuts down (e.g. LM 'X' requested 61 + notification of LM 'Y' boots or shuts down, when LM 'Y' boots or shuts down, 62 + SCMI firmware will send notification to LM 'X'). 63 + 64 + 'Graceful' means asking LM itself to shutdown/reset/etc (e.g. sending 65 + notification to Linux, Then Linux reboots or powers down itself). It is async 66 + command that the SUCCESS of the command just means the command successfully 67 + return, not means reboot/reset successfully finished. 68 + 69 + 'Forceful' means the SM will force shutdown/reset/etc the LM. It is sync 70 + command that the SUCCESS of the command means the LM has been successfully 71 + shutdown/reset/etc. 72 + If the commands not have Graceful/Forceful flag settings, such as WAKE, SUSEND, 73 + it is a Graceful command. 74 + 75 + Commands: 76 + _________ 77 + 78 + PROTOCOL_VERSION 79 + ~~~~~~~~~~~~~~~~ 80 + 81 + message_id: 0x0 82 + protocol_id: 0x80 83 + This command is mandatory. 84 + 85 + +---------------+--------------------------------------------------------------+ 86 + |Return values | 87 + +---------------+--------------------------------------------------------------+ 88 + |Name |Description | 89 + +---------------+--------------------------------------------------------------+ 90 + |int32 status | See ARM SCMI Specification for status code definitions. | 91 + +---------------+--------------------------------------------------------------+ 92 + |uint32 version | For this revision of the specification, this value must be | 93 + | | 0x10000. | 94 + +---------------+--------------------------------------------------------------+ 95 + 96 + PROTOCOL_ATTRIBUTES 97 + ~~~~~~~~~~~~~~~~~~~ 98 + 99 + message_id: 0x1 100 + protocol_id: 0x80 101 + This command is mandatory. 102 + 103 + +------------------+-----------------------------------------------------------+ 104 + |Return values | 105 + +------------------+-----------------------------------------------------------+ 106 + |Name |Description | 107 + +------------------+-----------------------------------------------------------+ 108 + |int32 status | See ARM SCMI Specification for status code definitions. | 109 + +------------------+-----------------------------------------------------------+ 110 + |uint32 attributes |Protocol attributes: | 111 + | |Bits[31:5] Reserved, must be zero. | 112 + | |Bits[4:0] Number of Logical Machines | 113 + | |Note that due to both hardware limitations and reset reason| 114 + | |field limitations, the max number of LM is 16. The minimum | 115 + | |is 1. | 116 + +------------------+-----------------------------------------------------------+ 117 + 118 + PROTOCOL_MESSAGE_ATTRIBUTES 119 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 120 + 121 + message_id: 0x2 122 + protocol_id: 0x80 123 + This command is mandatory. 124 + 125 + +------------------+-----------------------------------------------------------+ 126 + |Return values | 127 + +------------------+-----------------------------------------------------------+ 128 + |Name |Description | 129 + +------------------+-----------------------------------------------------------+ 130 + |int32 status |SUCCESS: in case the message is implemented and available | 131 + | |to use. | 132 + | |NOT_FOUND: if the message identified by message_id is | 133 + | |invalid or not implemented | 134 + +------------------+-----------------------------------------------------------+ 135 + |uint32 attributes |Flags that are associated with a specific command in the | 136 + | |protocol. For all commands in this protocol, this | 137 + | |parameter has a value of 0 | 138 + +------------------+-----------------------------------------------------------+ 139 + 140 + LMM_ATTRIBUTES 141 + ~~~~~~~~~~~~~~ 142 + 143 + message_id: 0x3 144 + protocol_id: 0x80 145 + This command is mandatory. 146 + 147 + +------------------+-----------------------------------------------------------+ 148 + |Parameters | 149 + +------------------+-----------------------------------------------------------+ 150 + |Name |Description | 151 + +------------------+-----------------------------------------------------------+ 152 + |uint32 lmid |ID of the Logical Machine | 153 + +------------------+-----------------------------------------------------------+ 154 + |Return values | 155 + +------------------+-----------------------------------------------------------+ 156 + |Name |Description | 157 + +------------------+-----------------------------------------------------------+ 158 + |int32 status |SUCCESS: if valid attributes are returned. | 159 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 160 + | |DENIED: if the agent does not have permission to get info | 161 + | |for the LM specified by lmid. | 162 + +------------------+-----------------------------------------------------------+ 163 + |uint32 lmid |Identifier of the LM whose identification is requested. | 164 + | |This field is: Populated with the lmid of the calling | 165 + | |agent, when the lmid parameter passed via the command is | 166 + | |0xFFFFFFFF. Identical to the lmid field passed via the | 167 + | |calling parameters, in all other cases | 168 + +------------------+-----------------------------------------------------------+ 169 + |uint32 attributes | Bits[31:0] reserved. must be zero | 170 + +------------------+-----------------------------------------------------------+ 171 + |uint32 state | Current state of the LM | 172 + +------------------+-----------------------------------------------------------+ 173 + |uint32 errStatus | Last error status recorded | 174 + +------------------+-----------------------------------------------------------+ 175 + |char name[16] | A NULL terminated ASCII string with the LM name, of up | 176 + | | to 16 bytes | 177 + +------------------+-----------------------------------------------------------+ 178 + 179 + LMM_BOOT 180 + ~~~~~~~~ 181 + 182 + message_id: 0x4 183 + protocol_id: 0x80 184 + This command is mandatory. 185 + 186 + +------------------+-----------------------------------------------------------+ 187 + |Parameters | 188 + +------------------+-----------------------------------------------------------+ 189 + |Name |Description | 190 + +------------------+-----------------------------------------------------------+ 191 + |uint32 lmid |ID of the Logical Machine | 192 + +------------------+-----------------------------------------------------------+ 193 + |Return values | 194 + +------------------+-----------------------------------------------------------+ 195 + |Name |Description | 196 + +------------------+-----------------------------------------------------------+ 197 + |int32 status |SUCCESS: if LM boots successfully started. | 198 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 199 + | |INVALID_PARAMETERS: if lmid is same as the caller. | 200 + | |DENIED: if the agent does not have permission to manage the| 201 + | |the LM specified by lmid. | 202 + +------------------+-----------------------------------------------------------+ 203 + 204 + LMM_RESET 205 + ~~~~~~~~~ 206 + 207 + message_id: 0x5 208 + protocol_id: 0x80 209 + This command is mandatory. 210 + 211 + +------------------+-----------------------------------------------------------+ 212 + |Parameters | 213 + +------------------+-----------------------------------------------------------+ 214 + |Name |Description | 215 + +------------------+-----------------------------------------------------------+ 216 + |uint32 lmid |ID of the Logical Machine | 217 + +------------------+-----------------------------------------------------------+ 218 + |uint32 flags |Reset flags: | 219 + | |Bits[31:1] Reserved, must be zero. | 220 + | |Bit[0] Graceful request: | 221 + | |Set to 1 if the request is a graceful request. | 222 + | |Set to 0 if the request is a forceful request. | 223 + +------------------+-----------------------------------------------------------+ 224 + |Return values | 225 + +------------------+-----------------------------------------------------------+ 226 + |Name |Description | 227 + +------------------+-----------------------------------------------------------+ 228 + |int32 status |SUCCESS: The LMM RESET command finished successfully in | 229 + | |graceful reset or LM successfully resets in forceful reset.| 230 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 231 + | |INVALID_PARAMETERS: if lmid is same as the caller. | 232 + | |DENIED: if the agent does not have permission to manage the| 233 + | |the LM specified by lmid. | 234 + +------------------+-----------------------------------------------------------+ 235 + 236 + LMM_SHUTDOWN 237 + ~~~~~~~~~~~~ 238 + 239 + message_id: 0x6 240 + protocol_id: 0x80 241 + This command is mandatory. 242 + 243 + +------------------+-----------------------------------------------------------+ 244 + |Parameters | 245 + +------------------+-----------------------------------------------------------+ 246 + |Name |Description | 247 + +------------------+-----------------------------------------------------------+ 248 + |uint32 lmid |ID of the Logical Machine | 249 + +------------------+-----------------------------------------------------------+ 250 + |uint32 flags |Reset flags: | 251 + | |Bits[31:1] Reserved, must be zero. | 252 + | |Bit[0] Graceful request: | 253 + | |Set to 1 if the request is a graceful request. | 254 + | |Set to 0 if the request is a forceful request. | 255 + +------------------+-----------------------------------------------------------+ 256 + |Return values | 257 + +------------------+-----------------------------------------------------------+ 258 + |Name |Description | 259 + +------------------+-----------------------------------------------------------+ 260 + |int32 status |SUCCESS: The LMM shutdown command finished successfully in | 261 + | |graceful request or LM successfully shutdown in forceful | 262 + | |request. | 263 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 264 + | |INVALID_PARAMETERS: if lmid is same as the caller. | 265 + | |DENIED: if the agent does not have permission to manage the| 266 + | |the LM specified by lmid. | 267 + +------------------+-----------------------------------------------------------+ 268 + 269 + LMM_WAKE 270 + ~~~~~~~~ 271 + 272 + message_id: 0x7 273 + protocol_id: 0x80 274 + This command is mandatory. 275 + 276 + +------------------+-----------------------------------------------------------+ 277 + |Parameters | 278 + +------------------+-----------------------------------------------------------+ 279 + |Name |Description | 280 + +------------------+-----------------------------------------------------------+ 281 + |uint32 lmid |ID of the Logical Machine | 282 + +------------------+-----------------------------------------------------------+ 283 + |Return values | 284 + +------------------+-----------------------------------------------------------+ 285 + |Name |Description | 286 + +------------------+-----------------------------------------------------------+ 287 + |int32 status |SUCCESS: if LM wake command successfully returns. | 288 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 289 + | |INVALID_PARAMETERS: if lmid is same as the caller. | 290 + | |DENIED: if the agent does not have permission to manage the| 291 + | |the LM specified by lmid. | 292 + +------------------+-----------------------------------------------------------+ 293 + 294 + LMM_SUSPEND 295 + ~~~~~~~~~~~ 296 + 297 + message_id: 0x8 298 + protocol_id: 0x80 299 + This command is mandatory. 300 + 301 + +------------------+-----------------------------------------------------------+ 302 + |Parameters | 303 + +------------------+-----------------------------------------------------------+ 304 + |Name |Description | 305 + +------------------+-----------------------------------------------------------+ 306 + |uint32 lmid |ID of the Logical Machine | 307 + +------------------+-----------------------------------------------------------+ 308 + |Return values | 309 + +------------------+-----------------------------------------------------------+ 310 + |Name |Description | 311 + +------------------+-----------------------------------------------------------+ 312 + |int32 status |SUCCESS: if LM suspend command successfully returns. | 313 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 314 + | |INVALID_PARAMETERS: if lmid is same as the caller. | 315 + | |DENIED: if the agent does not have permission to manage the| 316 + | |the LM specified by lmid. | 317 + +------------------+-----------------------------------------------------------+ 318 + 319 + LMM_NOTIFY 320 + ~~~~~~~~~~ 321 + 322 + message_id: 0x9 323 + protocol_id: 0x80 324 + This command is mandatory. 325 + 326 + +------------------+-----------------------------------------------------------+ 327 + |Parameters | 328 + +------------------+-----------------------------------------------------------+ 329 + |Name |Description | 330 + +------------------+-----------------------------------------------------------+ 331 + |uint32 lmid |ID of the Logical Machine | 332 + +------------------+-----------------------------------------------------------+ 333 + |uint32 flags |Notification flags: | 334 + | |Bits[31:3] Reserved, must be zero. | 335 + | |Bit[3] Wake (resume) notification: | 336 + | |Set to 1 to send notification. | 337 + | |Set to 0 if no notification. | 338 + | |Bit[2] Suspend (sleep) notification: | 339 + | |Set to 1 to send notification. | 340 + | |Set to 0 if no notification. | 341 + | |Bit[1] Shutdown (off) notification: | 342 + | |Set to 1 to send notification. | 343 + | |Set to 0 if no notification. | 344 + | |Bit[0] Boot (on) notification: | 345 + | |Set to 1 to send notification. | 346 + | |Set to 0 if no notification | 347 + +------------------+-----------------------------------------------------------+ 348 + |Return values | 349 + +------------------+-----------------------------------------------------------+ 350 + |Name |Description | 351 + +------------------+-----------------------------------------------------------+ 352 + |int32 status |SUCCESS: if the notification state successfully updated. | 353 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 354 + | |INVALID_PARAMETERS: if input attributes flag specifies | 355 + | |unsupported or invalid configurations. | 356 + | |DENIED: if the agent does not have permission to request | 357 + | |the notification. | 358 + +------------------+-----------------------------------------------------------+ 359 + 360 + LMM_RESET_REASON 361 + ~~~~~~~~~~~~~~~~ 362 + 363 + message_id: 0xA 364 + protocol_id: 0x80 365 + This command is mandatory. 366 + 367 + This command is to return the reset reason that caused the last reset, such as 368 + POR, WDOG, JTAG and etc. 369 + 370 + +---------------------+--------------------------------------------------------+ 371 + |Parameters | 372 + +---------------------+--------------------------------------------------------+ 373 + |Name |Description | 374 + +---------------------+--------------------------------------------------------+ 375 + |uint32 lmid |ID of the Logical Machine | 376 + +---------------------+--------------------------------------------------------+ 377 + |Return values | 378 + +---------------------+--------------------------------------------------------+ 379 + |Name |Description | 380 + +---------------------+--------------------------------------------------------+ 381 + |int32 status |SUCCESS: if the reset reason of the LM successfully | 382 + | |updated. | 383 + | |NOT_FOUND: if lmid not points to a valid logical machine| 384 + | |DENIED: if the agent does not have permission to request| 385 + | |the reset reason. | 386 + +---------------------+--------------------------------------------------------+ 387 + |uint32 bootflags |Boot reason flags. This parameter has the format: | 388 + | |Bits[31] Valid. | 389 + | |Set to 1 if the entire reason is valid. | 390 + | |Set to 0 if the entire reason is not valid. | 391 + | |Bits[30:29] Reserved, must be zero. | 392 + | |Bit[28] Valid origin: | 393 + | |Set to 1 if the origin field is valid. | 394 + | |Set to 0 if the origin field is not valid. | 395 + | |Bits[27:24] Origin. | 396 + | |Logical Machine(LM) ID that causes the BOOT of this LM | 397 + | |Bit[23] Valid err ID: | 398 + | |Set to 1 if the error ID field is valid. | 399 + | |Set to 0 if the error ID field is not valid. | 400 + | |Bits[22:8] Error ID(Agent ID of the system). | 401 + | |Bit[7:0] Reason(WDOG, POR, FCCU and etc): | 402 + | |See the SRESR register description in the System | 403 + | |Reset Controller (SRC) section in SoC reference mannual | 404 + | |One reason maps to BIT(reason) in SRESR | 405 + +---------------------+--------------------------------------------------------+ 406 + |uint32 shutdownflags |Shutdown reason flags. This parameter has the format: | 407 + | |Bits[31] Valid. | 408 + | |Set to 1 if the entire reason is valid. | 409 + | |Set to 0 if the entire reason is not valid. | 410 + | |Bits[30:29] Number of valid extended info words. | 411 + | |Bit[28] Valid origin: | 412 + | |Set to 1 if the origin field is valid. | 413 + | |Set to 0 if the origin field is not valid. | 414 + | |Bits[27:24] Origin. | 415 + | |Logical Machine(LM) ID that causes the BOOT of this LM | 416 + | |Bit[23] Valid err ID: | 417 + | |Set to 1 if the error ID field is valid. | 418 + | |Set to 0 if the error ID field is not valid. | 419 + | |Bits[22:8] Error ID(Agent ID of the System). | 420 + | |Bit[7:0] Reason | 421 + | |See the SRESR register description in the System | 422 + | |Reset Controller (SRC) section in SoC reference mannual | 423 + | |One reason maps to BIT(reason) in SRESR | 424 + +---------------------+--------------------------------------------------------+ 425 + |uint32 extinfo[3] |Array of extended info words(e.g. fault pc) | 426 + +---------------------+--------------------------------------------------------+ 427 + 428 + LMM_POWER_ON 429 + ~~~~~~~~~~~~ 430 + 431 + message_id: 0xB 432 + protocol_id: 0x80 433 + This command is mandatory. 434 + 435 + +------------------+-----------------------------------------------------------+ 436 + |Parameters | 437 + +------------------+-----------------------------------------------------------+ 438 + |Name |Description | 439 + +------------------+-----------------------------------------------------------+ 440 + |uint32 lmid |ID of the Logical Machine | 441 + +------------------+-----------------------------------------------------------+ 442 + |Return values | 443 + +------------------+-----------------------------------------------------------+ 444 + |Name |Description | 445 + +------------------+-----------------------------------------------------------+ 446 + |int32 status |SUCCESS: if LM successfully powers on. | 447 + | |NOT_FOUND: if lmid not points to a valid logical machine. | 448 + | |INVALID_PARAMETERS: if lmid is same as the caller. | 449 + | |DENIED: if the agent does not have permission to manage the| 450 + | |the LM specified by lmid. | 451 + +------------------+-----------------------------------------------------------+ 452 + 453 + LMM_RESET_VECTOR_SET 454 + ~~~~~~~~~~~~~~~~~~~~ 455 + 456 + message_id: 0xC 457 + protocol_id: 0x80 458 + This command is mandatory. 459 + 460 + +-----------------------+------------------------------------------------------+ 461 + |Parameters | 462 + +-----------------------+------------------------------------------------------+ 463 + |Name |Description | 464 + +-----------------------+------------------------------------------------------+ 465 + |uint32 lmid |ID of the Logical Machine | 466 + +-----------------------+------------------------------------------------------+ 467 + |uint32 cpuid |ID of the CPU inside the LM | 468 + +-----------------------+------------------------------------------------------+ 469 + |uint32 flags |Reset vector flags | 470 + | |Bits[31:0] Reserved, must be zero. | 471 + +-----------------------+------------------------------------------------------+ 472 + |uint32 resetVectorLow |Lower vector | 473 + +-----------------------+------------------------------------------------------+ 474 + |uint32 resetVectorHigh |Higher vector | 475 + +-----------------------+------------------------------------------------------+ 476 + |Return values | 477 + +-----------------------+------------------------------------------------------+ 478 + |Name |Description | 479 + +-----------------------+------------------------------------------------------+ 480 + |int32 status |SUCCESS: If reset vector is set successfully. | 481 + | |NOT_FOUND: if lmid not points to a valid logical | 482 + | |machine, or cpuId is not valid. | 483 + | |INVALID_PARAMETERS: if reset vector is invalid. | 484 + | |DENIED: if the agent does not have permission to set | 485 + | |the reset vector for the CPU in the LM. | 486 + +-----------------------+------------------------------------------------------+ 487 + 488 + NEGOTIATE_PROTOCOL_VERSION 489 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 490 + 491 + message_id: 0x10 492 + protocol_id: 0x80 493 + This command is mandatory. 494 + 495 + +--------------------+---------------------------------------------------------+ 496 + |Parameters | 497 + +--------------------+---------------------------------------------------------+ 498 + |Name |Description | 499 + +--------------------+---------------------------------------------------------+ 500 + |uint32 version |The negotiated protocol version the agent intends to use | 501 + +--------------------+---------------------------------------------------------+ 502 + |Return values | 503 + +--------------------+---------------------------------------------------------+ 504 + |Name |Description | 505 + +--------------------+---------------------------------------------------------+ 506 + |int32 status |SUCCESS: if the negotiated protocol version is supported | 507 + | |by the platform. All commands, responses, and | 508 + | |notifications post successful return of this command must| 509 + | |comply with the negotiated version. | 510 + | |NOT_SUPPORTED: if the protocol version is not supported. | 511 + +--------------------+---------------------------------------------------------+ 512 + 513 + Notifications 514 + _____________ 515 + 516 + LMM_EVENT 517 + ~~~~~~~~~ 518 + 519 + message_id: 0x0 520 + protocol_id: 0x80 521 + 522 + +------------------+-----------------------------------------------------------+ 523 + |Parameters | 524 + +------------------+-----------------------------------------------------------+ 525 + |Name |Description | 526 + +------------------+-----------------------------------------------------------+ 527 + |uint32 lmid |Identifier for the LM that caused the transition. | 528 + +------------------+-----------------------------------------------------------+ 529 + |uint32 eventlm |Identifier of the LM this event refers to. | 530 + +------------------+-----------------------------------------------------------+ 531 + |uint32 flags |LM events: | 532 + | |Bits[31:3] Reserved, must be zero. | 533 + | |Bit[3] Wake (resume) event: | 534 + | |1 LM has awakened. | 535 + | |0 not a wake event. | 536 + | |Bit[2] Suspend (sleep) event: | 537 + | |1 LM has suspended. | 538 + | |0 not a suspend event. | 539 + | |Bit[1] Shutdown (off) event: | 540 + | |1 LM has shutdown. | 541 + | |0 not a shutdown event. | 542 + | |Bit[0] Boot (on) event: | 543 + | |1 LM has booted. | 544 + | |0 not a boot event. | 545 + +------------------+-----------------------------------------------------------+ 546 + 35 547 SCMI_BBM: System Control and Management BBM Vendor Protocol 36 548 ============================================================== 37 549 ··· 947 435 | |1 button change detected. | 948 436 | |0 no button change detected. | 949 437 +------------------+-----------------------------------------------------------+ 438 + 439 + System Control and Management CPU Vendor Protocol 440 + ================================================= 441 + 442 + This protocol allows an agent to start or stop a CPU. It is used to manage 443 + auxiliary CPUs in a target LM (e.g. additional cores in an AP cluster or 444 + Cortex-M cores). 445 + Note: 446 + - For cores in AP cluster, PSCI should be used and PSCI firmware will use CPU 447 + protocol to handle them. For cores in non-AP cluster, Operating System(e.g. 448 + Linux OS) could use CPU protocols to control Cortex-M7 cores. 449 + - CPU indicates the core and its auxiliary peripherals(e.g. TCM) inside 450 + i.MX SoC 451 + 452 + There are cases where giving an agent full control of a CPU via the CPU 453 + protocol is not desired. The LMM protocol is more restricted to just boot, 454 + shutdown, etc. So an agent might boot another logical machine but not be 455 + able to directly mess the state of its CPUs. Its also the reason there is an 456 + LMM power on command even though that could have been done through the 457 + power protocol. 458 + 459 + The CPU protocol provides commands to: 460 + 461 + - Describe the protocol version. 462 + - Discover implementation attributes. 463 + - Discover the CPUs defined in the system. 464 + - Start a CPU. 465 + - Stop a CPU. 466 + - Set the boot and resume addresses for a CPU. 467 + - Set the sleep mode of a CPU. 468 + - Configure wake-up sources for a CPU. 469 + - Configure power domain reactions (LPM mode and retention mask) for a CPU. 470 + - The CPU IDs can be found in the CPU section of the SoC DEVICE: SM Device 471 + Interface. They can also be found in the SoC RM. See the CPU Mode Control 472 + (CMC) list in General Power Controller (GPC) section. 473 + 474 + CPU settings are not aggregated and setting their state is normally exclusive 475 + to one client. 476 + 477 + Commands: 478 + _________ 479 + 480 + PROTOCOL_VERSION 481 + ~~~~~~~~~~~~~~~~ 482 + 483 + message_id: 0x0 484 + protocol_id: 0x82 485 + This command is mandatory. 486 + 487 + +---------------+--------------------------------------------------------------+ 488 + |Return values | 489 + +---------------+--------------------------------------------------------------+ 490 + |Name |Description | 491 + +---------------+--------------------------------------------------------------+ 492 + |int32 status | See ARM SCMI Specification for status code definitions. | 493 + +---------------+--------------------------------------------------------------+ 494 + |uint32 version | For this revision of the specification, this value must be | 495 + | | 0x10000. | 496 + +---------------+--------------------------------------------------------------+ 497 + 498 + PROTOCOL_ATTRIBUTES 499 + ~~~~~~~~~~~~~~~~~~~ 500 + 501 + message_id: 0x1 502 + protocol_id: 0x82 503 + This command is mandatory. 504 + 505 + +---------------+--------------------------------------------------------------+ 506 + |Return values | 507 + +------------------+-----------------------------------------------------------+ 508 + |Name |Description | 509 + +------------------+-----------------------------------------------------------+ 510 + |int32 status | See ARM SCMI Specification for status code definitions. | 511 + +------------------+-----------------------------------------------------------+ 512 + |uint32 attributes |Protocol attributes: | 513 + | |Bits[31:16] Reserved, must be zero. | 514 + | |Bits[15:0] Number of CPUs | 515 + +------------------+-----------------------------------------------------------+ 516 + 517 + PROTOCOL_MESSAGE_ATTRIBUTES 518 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 519 + 520 + message_id: 0x2 521 + protocol_id: 0x82 522 + This command is mandatory. 523 + 524 + +---------------+--------------------------------------------------------------+ 525 + |Return values | 526 + +------------------+-----------------------------------------------------------+ 527 + |Name |Description | 528 + +------------------+-----------------------------------------------------------+ 529 + |int32 status |SUCCESS: in case the message is implemented and available | 530 + | |to use. | 531 + | |NOT_FOUND: if the message identified by message_id is | 532 + | |invalid or not implemented | 533 + +------------------+-----------------------------------------------------------+ 534 + |uint32 attributes |Flags that are associated with a specific command in the | 535 + | |protocol. For all commands in this protocol, this | 536 + | |parameter has a value of 0 | 537 + +------------------+-----------------------------------------------------------+ 538 + 539 + CPU_ATTRIBUTES 540 + ~~~~~~~~~~~~~~ 541 + 542 + message_id: 0x4 543 + protocol_id: 0x82 544 + This command is mandatory. 545 + 546 + +------------------+-----------------------------------------------------------+ 547 + |Parameters | 548 + +------------------+-----------------------------------------------------------+ 549 + |Name |Description | 550 + +------------------+-----------------------------------------------------------+ 551 + |uint32 cpuid |Identifier for the CPU | 552 + +------------------+-----------------------------------------------------------+ 553 + |Return values | 554 + +------------------+-----------------------------------------------------------+ 555 + |Name |Description | 556 + +------------------+-----------------------------------------------------------+ 557 + |int32 status |SUCCESS: if valid attributes are returned successfully. | 558 + | |NOT_FOUND: if the cpuid is not valid. | 559 + +------------------+-----------------------------------------------------------+ 560 + |uint32 attributes |Bits[31:0] Reserved, must be zero | 561 + +------------------+-----------------------------------------------------------+ 562 + |char name[16] |NULL terminated ASCII string with CPU name up to 16 bytes | 563 + +------------------+-----------------------------------------------------------+ 564 + 565 + CPU_START 566 + ~~~~~~~~~ 567 + 568 + message_id: 0x4 569 + protocol_id: 0x82 570 + This command is mandatory. 571 + 572 + +------------------+-----------------------------------------------------------+ 573 + |Parameters | 574 + +------------------+-----------------------------------------------------------+ 575 + |Name |Description | 576 + +------------------+-----------------------------------------------------------+ 577 + |uint32 cpuid |Identifier for the CPU | 578 + +------------------+-----------------------------------------------------------+ 579 + |Return values | 580 + +------------------+-----------------------------------------------------------+ 581 + |Name |Description | 582 + +------------------+-----------------------------------------------------------+ 583 + |int32 status |SUCCESS: if the cpu is started successfully. | 584 + | |NOT_FOUND: if cpuid is not valid. | 585 + | |DENIED: the calling agent is not allowed to start this CPU.| 586 + +------------------+-----------------------------------------------------------+ 587 + 588 + CPU_STOP 589 + ~~~~~~~~ 590 + 591 + message_id: 0x5 592 + protocol_id: 0x82 593 + This command is mandatory. 594 + 595 + +------------------+-----------------------------------------------------------+ 596 + |Parameters | 597 + +------------------+-----------------------------------------------------------+ 598 + |Name |Description | 599 + +------------------+-----------------------------------------------------------+ 600 + |uint32 cpuid |Identifier for the CPU | 601 + +------------------+-----------------------------------------------------------+ 602 + |Return values | 603 + +------------------+-----------------------------------------------------------+ 604 + |Name |Description | 605 + +------------------+-----------------------------------------------------------+ 606 + |int32 status |SUCCESS: if the cpu is started successfully. | 607 + | |NOT_FOUND: if cpuid is not valid. | 608 + | |DENIED: the calling agent is not allowed to stop this CPU. | 609 + +------------------+-----------------------------------------------------------+ 610 + 611 + CPU_RESET_VECTOR_SET 612 + ~~~~~~~~~~~~~~~~~~~~ 613 + 614 + message_id: 0x6 615 + protocol_id: 0x82 616 + This command is mandatory. 617 + 618 + +----------------------+-------------------------------------------------------+ 619 + |Parameters | 620 + +----------------------+-------------------------------------------------------+ 621 + |Name |Description | 622 + +----------------------+-------------------------------------------------------+ 623 + |uint32 cpuid |Identifier for the CPU | 624 + +----------------------+-------------------------------------------------------+ 625 + |uint32 flags |Reset vector flags: | 626 + | |Bit[31] Resume flag. | 627 + | |Set to 1 to update the reset vector used on resume. | 628 + | |Bit[30] Boot flag. | 629 + | |Set to 1 to update the reset vector used for boot. | 630 + | |Bits[29:1] Reserved, must be zero. | 631 + | |Bit[0] Table flag. | 632 + | |Set to 1 if vector is the vector table base address. | 633 + +----------------------+-------------------------------------------------------+ 634 + |uint32 resetVectorLow |Lower vector: | 635 + | |If bit[0] of flags is 0, the lower 32 bits of the | 636 + | |physical address where the CPU should execute from on | 637 + | |reset. If bit[0] of flags is 1, the lower 32 bits of | 638 + | |the vector table base address | 639 + +----------------------+-------------------------------------------------------+ 640 + |uint32 resetVectorhigh|Upper vector: | 641 + | |If bit[0] of flags is 0, the upper 32 bits of the | 642 + | |physical address where the CPU should execute from on | 643 + | |reset. If bit[0] of flags is 1, the upper 32 bits of | 644 + | |the vector table base address | 645 + +----------------------+-------------------------------------------------------+ 646 + |Return values | 647 + +----------------------+-------------------------------------------------------+ 648 + |Name |Description | 649 + +----------------------+-------------------------------------------------------+ 650 + |int32 status |SUCCESS: if the CPU reset vector is set successfully. | 651 + | |NOT_FOUND: if cpuId does not point to a valid CPU. | 652 + | |INVALID_PARAMETERS: the requested vector type is not | 653 + | |supported by this CPU. | 654 + | |DENIED: the calling agent is not allowed to set the | 655 + | |reset vector of this CPU | 656 + +----------------------+-------------------------------------------------------+ 657 + 658 + CPU_SLEEP_MODE_SET 659 + ~~~~~~~~~~~~~~~~~~ 660 + 661 + message_id: 0x7 662 + protocol_id: 0x82 663 + This command is mandatory. 664 + 665 + +----------------------+-------------------------------------------------------+ 666 + |Parameters | 667 + +----------------------+-------------------------------------------------------+ 668 + |Name |Description | 669 + +----------------------+-------------------------------------------------------+ 670 + |uint32 cpuid |Identifier for the CPU | 671 + +----------------------+-------------------------------------------------------+ 672 + |uint32 flags |Sleep mode flags: | 673 + | |Bits[31:1] Reserved, must be zero. | 674 + | |Bit[0] IRQ mux: | 675 + | |If set to 1 the wakeup mux source is the GIC, else if 0| 676 + | |then the GPC | 677 + +----------------------+-------------------------------------------------------+ 678 + |uint32 sleepmode |target sleep mode. When CPU runs into WFI, the GPC mode| 679 + | |will be triggered to be in below modes: | 680 + | |RUN: (0) | 681 + | |WAIT: (1) | 682 + | |STOP: (2) | 683 + | |SUSPEND: (3) | 684 + +----------------------+-------------------------------------------------------+ 685 + |Return values | 686 + +----------------------+-------------------------------------------------------+ 687 + |Name |Description | 688 + +----------------------+-------------------------------------------------------+ 689 + |int32 status |SUCCESS: if the CPU sleep mode is set successfully. | 690 + | |NOT_FOUND: if cpuId does not point to a valid CPU. | 691 + | |INVALID_PARAMETERS: the sleepmode or flags is invalid. | 692 + | |DENIED: the calling agent is not allowed to configure | 693 + | |the CPU | 694 + +----------------------+-------------------------------------------------------+ 695 + 696 + CPU_INFO_GET 697 + ~~~~~~~~~~~~ 698 + 699 + message_id: 0xC 700 + protocol_id: 0x82 701 + This command is mandatory. 702 + 703 + +----------------------+-------------------------------------------------------+ 704 + |Parameters | 705 + +----------------------+-------------------------------------------------------+ 706 + |Name |Description | 707 + +----------------------+-------------------------------------------------------+ 708 + |uint32 cpuid |Identifier for the CPU | 709 + +----------------------+-------------------------------------------------------+ 710 + |Return values | 711 + +----------------------+-------------------------------------------------------+ 712 + |Name |Description | 713 + +----------------------+-------------------------------------------------------+ 714 + |int32 status |SUCCESS: if valid attributes are returned successfully.| 715 + | |NOT_FOUND: if the cpuid is not valid. | 716 + +----------------------+-------------------------------------------------------+ 717 + |uint32 runmode |Run mode for the CPU | 718 + | |RUN(0):cpu started | 719 + | |HOLD(1):cpu powered up and reset asserted | 720 + | |STOP(2):cpu reseted and hold cpu | 721 + | |SUSPEND(3):in cpuidle state | 722 + +----------------------+-------------------------------------------------------+ 723 + |uint32 sleepmode |Sleep mode for the CPU, see CPU_SLEEP_MODE_SET | 724 + +----------------------+-------------------------------------------------------+ 725 + |uint32 resetvectorlow |Reset vector low 32 bits for the CPU | 726 + +----------------------+-------------------------------------------------------+ 727 + |uint32 resetvecothigh |Reset vector high 32 bits for the CPU | 728 + +----------------------+-------------------------------------------------------+ 729 + 730 + NEGOTIATE_PROTOCOL_VERSION 731 + ~~~~~~~~~~~~~~~~~~~~~~~~~~ 732 + 733 + message_id: 0x10 734 + protocol_id: 0x82 735 + This command is mandatory. 736 + 737 + +--------------------+---------------------------------------------------------+ 738 + |Parameters | 739 + +--------------------+---------------------------------------------------------+ 740 + |Name |Description | 741 + +--------------------+---------------------------------------------------------+ 742 + |uint32 version |The negotiated protocol version the agent intends to use | 743 + +--------------------+---------------------------------------------------------+ 744 + |Return values | 745 + +--------------------+---------------------------------------------------------+ 746 + |Name |Description | 747 + +--------------------+---------------------------------------------------------+ 748 + |int32 status |SUCCESS: if the negotiated protocol version is supported | 749 + | |by the platform. All commands, responses, and | 750 + | |notifications post successful return of this command must| 751 + | |comply with the negotiated version. | 752 + | |NOT_SUPPORTED: if the protocol version is not supported. | 753 + +--------------------+---------------------------------------------------------+ 950 754 951 755 SCMI_MISC: System Control and Management MISC Vendor Protocol 952 756 ================================================================
+22
drivers/firmware/imx/Kconfig
··· 23 23 This driver manages the IPC interface between host CPU and the 24 24 SCU firmware running on M4. 25 25 26 + config IMX_SCMI_CPU_DRV 27 + tristate "IMX SCMI CPU Protocol driver" 28 + depends on ARCH_MXC || COMPILE_TEST 29 + default y if ARCH_MXC 30 + help 31 + The System Controller Management Interface firmware (SCMI FW) is 32 + a low-level system function which runs on a dedicated Cortex-M 33 + core that could provide cpu management features. 34 + 35 + This driver can also be built as a module. 36 + 37 + config IMX_SCMI_LMM_DRV 38 + tristate "IMX SCMI LMM Protocol driver" 39 + depends on ARCH_MXC || COMPILE_TEST 40 + default y if ARCH_MXC 41 + help 42 + The System Controller Management Interface firmware (SCMI FW) is 43 + a low-level system function which runs on a dedicated Cortex-M 44 + core that could provide Logical Machine management features. 45 + 46 + This driver can also be built as a module. 47 + 26 48 config IMX_SCMI_MISC_DRV 27 49 tristate "IMX SCMI MISC Protocol driver" 28 50 depends on ARCH_MXC || COMPILE_TEST
+2
drivers/firmware/imx/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_IMX_DSP) += imx-dsp.o 3 3 obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o 4 + obj-${CONFIG_IMX_SCMI_CPU_DRV} += sm-cpu.o 4 5 obj-${CONFIG_IMX_SCMI_MISC_DRV} += sm-misc.o 6 + obj-${CONFIG_IMX_SCMI_LMM_DRV} += sm-lmm.o
+85
drivers/firmware/imx/sm-cpu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2025 NXP 4 + */ 5 + 6 + #include <linux/firmware/imx/sm.h> 7 + #include <linux/module.h> 8 + #include <linux/of.h> 9 + #include <linux/platform_device.h> 10 + #include <linux/scmi_protocol.h> 11 + #include <linux/scmi_imx_protocol.h> 12 + 13 + static const struct scmi_imx_cpu_proto_ops *imx_cpu_ops; 14 + static struct scmi_protocol_handle *ph; 15 + 16 + int scmi_imx_cpu_reset_vector_set(u32 cpuid, u64 vector, bool start, bool boot, 17 + bool resume) 18 + { 19 + if (!ph) 20 + return -EPROBE_DEFER; 21 + 22 + return imx_cpu_ops->cpu_reset_vector_set(ph, cpuid, vector, start, 23 + boot, resume); 24 + } 25 + EXPORT_SYMBOL(scmi_imx_cpu_reset_vector_set); 26 + 27 + int scmi_imx_cpu_start(u32 cpuid, bool start) 28 + { 29 + if (!ph) 30 + return -EPROBE_DEFER; 31 + 32 + if (start) 33 + return imx_cpu_ops->cpu_start(ph, cpuid, true); 34 + 35 + return imx_cpu_ops->cpu_start(ph, cpuid, false); 36 + }; 37 + EXPORT_SYMBOL(scmi_imx_cpu_start); 38 + 39 + int scmi_imx_cpu_started(u32 cpuid, bool *started) 40 + { 41 + if (!ph) 42 + return -EPROBE_DEFER; 43 + 44 + if (!started) 45 + return -EINVAL; 46 + 47 + return imx_cpu_ops->cpu_started(ph, cpuid, started); 48 + }; 49 + EXPORT_SYMBOL(scmi_imx_cpu_started); 50 + 51 + static int scmi_imx_cpu_probe(struct scmi_device *sdev) 52 + { 53 + const struct scmi_handle *handle = sdev->handle; 54 + 55 + if (!handle) 56 + return -ENODEV; 57 + 58 + if (imx_cpu_ops) { 59 + dev_err(&sdev->dev, "sm cpu already initialized\n"); 60 + return -EEXIST; 61 + } 62 + 63 + imx_cpu_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_CPU, &ph); 64 + if (IS_ERR(imx_cpu_ops)) 65 + return PTR_ERR(imx_cpu_ops); 66 + 67 + return 0; 68 + } 69 + 70 + static const struct scmi_device_id scmi_id_table[] = { 71 + { SCMI_PROTOCOL_IMX_CPU, "imx-cpu" }, 72 + { }, 73 + }; 74 + MODULE_DEVICE_TABLE(scmi, scmi_id_table); 75 + 76 + static struct scmi_driver scmi_imx_cpu_driver = { 77 + .name = "scmi-imx-cpu", 78 + .probe = scmi_imx_cpu_probe, 79 + .id_table = scmi_id_table, 80 + }; 81 + module_scmi_driver(scmi_imx_cpu_driver); 82 + 83 + MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 84 + MODULE_DESCRIPTION("IMX SM CPU driver"); 85 + MODULE_LICENSE("GPL");
+91
drivers/firmware/imx/sm-lmm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2025 NXP 4 + */ 5 + 6 + #include <linux/firmware/imx/sm.h> 7 + #include <linux/module.h> 8 + #include <linux/of.h> 9 + #include <linux/platform_device.h> 10 + #include <linux/scmi_protocol.h> 11 + #include <linux/scmi_imx_protocol.h> 12 + 13 + static const struct scmi_imx_lmm_proto_ops *imx_lmm_ops; 14 + static struct scmi_protocol_handle *ph; 15 + 16 + int scmi_imx_lmm_info(u32 lmid, struct scmi_imx_lmm_info *info) 17 + { 18 + if (!ph) 19 + return -EPROBE_DEFER; 20 + 21 + if (!info) 22 + return -EINVAL; 23 + 24 + return imx_lmm_ops->lmm_info(ph, lmid, info); 25 + }; 26 + EXPORT_SYMBOL(scmi_imx_lmm_info); 27 + 28 + int scmi_imx_lmm_reset_vector_set(u32 lmid, u32 cpuid, u32 flags, u64 vector) 29 + { 30 + if (!ph) 31 + return -EPROBE_DEFER; 32 + 33 + return imx_lmm_ops->lmm_reset_vector_set(ph, lmid, cpuid, flags, vector); 34 + } 35 + EXPORT_SYMBOL(scmi_imx_lmm_reset_vector_set); 36 + 37 + int scmi_imx_lmm_operation(u32 lmid, enum scmi_imx_lmm_op op, u32 flags) 38 + { 39 + if (!ph) 40 + return -EPROBE_DEFER; 41 + 42 + switch (op) { 43 + case SCMI_IMX_LMM_BOOT: 44 + return imx_lmm_ops->lmm_power_boot(ph, lmid, true); 45 + case SCMI_IMX_LMM_POWER_ON: 46 + return imx_lmm_ops->lmm_power_boot(ph, lmid, false); 47 + case SCMI_IMX_LMM_SHUTDOWN: 48 + return imx_lmm_ops->lmm_shutdown(ph, lmid, flags); 49 + default: 50 + break; 51 + } 52 + 53 + return -EINVAL; 54 + } 55 + EXPORT_SYMBOL(scmi_imx_lmm_operation); 56 + 57 + static int scmi_imx_lmm_probe(struct scmi_device *sdev) 58 + { 59 + const struct scmi_handle *handle = sdev->handle; 60 + 61 + if (!handle) 62 + return -ENODEV; 63 + 64 + if (imx_lmm_ops) { 65 + dev_err(&sdev->dev, "lmm already initialized\n"); 66 + return -EEXIST; 67 + } 68 + 69 + imx_lmm_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_LMM, &ph); 70 + if (IS_ERR(imx_lmm_ops)) 71 + return PTR_ERR(imx_lmm_ops); 72 + 73 + return 0; 74 + } 75 + 76 + static const struct scmi_device_id scmi_id_table[] = { 77 + { SCMI_PROTOCOL_IMX_LMM, "imx-lmm" }, 78 + { }, 79 + }; 80 + MODULE_DEVICE_TABLE(scmi, scmi_id_table); 81 + 82 + static struct scmi_driver scmi_imx_lmm_driver = { 83 + .name = "scmi-imx-lmm", 84 + .probe = scmi_imx_lmm_probe, 85 + .id_table = scmi_id_table, 86 + }; 87 + module_scmi_driver(scmi_imx_lmm_driver); 88 + 89 + MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 90 + MODULE_DESCRIPTION("IMX SM LMM driver"); 91 + MODULE_LICENSE("GPL");
+19
include/linux/firmware/imx/sm.h
··· 8 8 9 9 #include <linux/bitfield.h> 10 10 #include <linux/errno.h> 11 + #include <linux/scmi_imx_protocol.h> 11 12 #include <linux/types.h> 12 13 13 14 #define SCMI_IMX_CTRL_PDM_CLK_SEL 0 /* AON PDM clock sel */ ··· 21 20 int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val); 22 21 int scmi_imx_misc_ctrl_set(u32 id, u32 val); 23 22 23 + int scmi_imx_cpu_start(u32 cpuid, bool start); 24 + int scmi_imx_cpu_started(u32 cpuid, bool *started); 25 + int scmi_imx_cpu_reset_vector_set(u32 cpuid, u64 vector, bool start, bool boot, 26 + bool resume); 27 + 28 + enum scmi_imx_lmm_op { 29 + SCMI_IMX_LMM_BOOT, 30 + SCMI_IMX_LMM_POWER_ON, 31 + SCMI_IMX_LMM_SHUTDOWN, 32 + }; 33 + 34 + /* For shutdown pperation */ 35 + #define SCMI_IMX_LMM_OP_FORCEFUL 0 36 + #define SCMI_IMX_LMM_OP_GRACEFUL BIT(0) 37 + 38 + int scmi_imx_lmm_operation(u32 lmid, enum scmi_imx_lmm_op op, u32 flags); 39 + int scmi_imx_lmm_info(u32 lmid, struct scmi_imx_lmm_info *info); 40 + int scmi_imx_lmm_reset_vector_set(u32 lmid, u32 cpuid, u32 flags, u64 vector); 24 41 #endif
+42
include/linux/scmi_imx_protocol.h
··· 11 11 #include <linux/bitfield.h> 12 12 #include <linux/device.h> 13 13 #include <linux/notifier.h> 14 + #include <linux/scmi_protocol.h> 14 15 #include <linux/types.h> 15 16 17 + #define SCMI_PROTOCOL_IMX_LMM 0x80 16 18 #define SCMI_PROTOCOL_IMX_BBM 0x81 19 + #define SCMI_PROTOCOL_IMX_CPU 0x82 17 20 #define SCMI_PROTOCOL_IMX_MISC 0x84 18 21 19 22 #define SCMI_IMX_VENDOR "NXP" ··· 59 56 u32 *num, u32 *val); 60 57 int (*misc_ctrl_req_notify)(const struct scmi_protocol_handle *ph, 61 58 u32 ctrl_id, u32 evt_id, u32 flags); 59 + }; 60 + 61 + /* See LMM_ATTRIBUTES in imx95.rst */ 62 + #define LMM_ID_DISCOVER 0xFFFFFFFFU 63 + #define LMM_MAX_NAME 16 64 + 65 + enum scmi_imx_lmm_state { 66 + LMM_STATE_LM_OFF, 67 + LMM_STATE_LM_ON, 68 + LMM_STATE_LM_SUSPEND, 69 + LMM_STATE_LM_POWERED, 70 + }; 71 + 72 + struct scmi_imx_lmm_info { 73 + u32 lmid; 74 + enum scmi_imx_lmm_state state; 75 + u32 errstatus; 76 + u8 name[LMM_MAX_NAME]; 77 + }; 78 + 79 + struct scmi_imx_lmm_proto_ops { 80 + int (*lmm_power_boot)(const struct scmi_protocol_handle *ph, u32 lmid, 81 + bool boot); 82 + int (*lmm_info)(const struct scmi_protocol_handle *ph, u32 lmid, 83 + struct scmi_imx_lmm_info *info); 84 + int (*lmm_reset_vector_set)(const struct scmi_protocol_handle *ph, 85 + u32 lmid, u32 cpuid, u32 flags, u64 vector); 86 + int (*lmm_shutdown)(const struct scmi_protocol_handle *ph, u32 lmid, 87 + u32 flags); 88 + }; 89 + 90 + struct scmi_imx_cpu_proto_ops { 91 + int (*cpu_reset_vector_set)(const struct scmi_protocol_handle *ph, 92 + u32 cpuid, u64 vector, bool start, 93 + bool boot, bool resume); 94 + int (*cpu_start)(const struct scmi_protocol_handle *ph, u32 cpuid, 95 + bool start); 96 + int (*cpu_started)(const struct scmi_protocol_handle *ph, u32 cpuid, 97 + bool *started); 62 98 }; 63 99 #endif