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

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

Arm SCMI updates for v6.12

Few main features include:

1. SCMI transport as stand-alone drivers

Currently the SCMI transport layer is being built embedded into in
the core SCMI stack. Some of these transports, despite being currently
part of the main SCMI module, are indeed also registered with different
subsystems like optee or virtio, and actively probed also by those.
This leads to a few awkward and convoluted tricks to properly handle
such interactions at boot time in the SCMI stack.

This change adds the new logic to the core SCMI stack so that each
existing transport is transitioned to be a standi-alone driver. With
that all the probe deferral and awkward retries between the SCMI
core stack and the transports has been removed, since no more needed.

2. Support for obtaining transport descriptors from the devicetree

SCMI platform firmwares might have different designs depending on
the platform. Some of the transport descriptors rely on such design.
E.g. the maximum receive channel timeout value might vary depending
on the specific underlying hardware and firmware design choices.

This change adds support for max-rx-timeout-ms property to describe
the transport needs of a specific platform design. It will be extended
in the future to obtain other such hardware/firmware dependent
transport related descriptors.

3. NXP i.MX95 specific SCMI vendor protocol extensions

SCMI specification allows vendor or platform-specific extensions to
the interface. NXP i.MX95 System Manager(SM) that implements SCMI
extends the interface to implement couple of vendor/platform specific
protocol, namely:
a. Battery Backed Module(BBM) Protocol

This protocol is intended provide access to the battery-backed
module. This contains persistent storage (GPR), an RTC, and the
ON/OFF button. The protocol can also provide access to similar
functions implemented via external board components.

b. MISC Protocol for misc settings

This includes controls that are misc settings/actions that must
be exposed from the SM to agents. They are device specific and
are usually define to access bit fields in various mix block
control modules, IOMUX_GPR, and other GPR/CSR owned by the SM.

4. SCMI debug/tracking metrics

Since SCMI involves interaction with the entity(software, firmware
and/or hardware) providing services or features, it is quite useful
to track certain metrics(for pure debugging purposes) like how many
messages were sent or received, were there any failures, what kind
of failures, ..etc. This feature adds support for the same via debugfs.

Apart from these main features, there are some miscellaneous updates, fixes
and cleanups.

* tag 'scmi-updates-6.12' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: (31 commits)
rtc: support i.MX95 BBM RTC
input: keyboard: support i.MX95 BBM module
firmware: imx: Add i.MX95 MISC driver
firmware: arm_scmi: Add initial support for i.MX MISC protocol
firmware: arm_scmi: Add initial support for i.MX BBM protocol
firmware: arm_scmi: Add NXP i.MX95 SCMI documentation
dt-bindings: firmware: Add i.MX95 SCMI Extension protocol
firmware: arm_scmi: Replace comma with the semicolon
firmware: arm_scmi: Replace the use of of_node_put() to __free(device_node)
firmware: arm_scmi: Fix trivial whitespace/coding style issues
firmware: arm_scmi: Use max-rx-timeout-ms from devicetree
dt-bindings: firmware: arm,scmi: Introduce property max-rx-timeout-ms
firmware: arm_scmi: Remove const from transport descriptors
firmware: arm_scmi: Simplify with scoped for each OF child loop
firmware: arm_scmi: Update various protocols versions
firmware: arm_scmi: Remove legacy transport-layer code
firmware: arm_scmi: Make VirtIO transport a standalone driver
firmware: arm_scmi: Make OPTEE transport a standalone driver
firmware: arm_scmi: Make SMC transport a standalone driver
firmware: arm_scmi: Make MBOX transport a standalone driver
...

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

+3053 -501
+19 -1
Documentation/devicetree/bindings/firmware/arm,scmi.yaml
··· 22 22 23 23 [0] https://developer.arm.com/documentation/den0056/latest 24 24 25 + anyOf: 26 + - $ref: /schemas/firmware/nxp,imx95-scmi.yaml 27 + 25 28 properties: 26 29 $nodename: 27 30 const: scmi ··· 124 121 atomic mode of operation, even if requested. 125 122 default: 0 126 123 124 + max-rx-timeout-ms: 125 + description: 126 + An optional time value, expressed in milliseconds, representing the 127 + transport maximum timeout value for the receive channel. The value should 128 + be a non-zero value if set. 129 + minimum: 1 130 + 127 131 arm,smc-id: 128 132 $ref: /schemas/types.yaml#/definitions/uint32 129 133 description: ··· 154 144 155 145 required: 156 146 - '#power-domain-cells' 147 + 148 + protocol@12: 149 + $ref: '#/$defs/protocol-node' 150 + unevaluatedProperties: false 151 + 152 + properties: 153 + reg: 154 + const: 0x12 157 155 158 156 protocol@13: 159 157 $ref: '#/$defs/protocol-node' ··· 302 284 required: 303 285 - reg 304 286 305 - additionalProperties: false 287 + unevaluatedProperties: false 306 288 307 289 $defs: 308 290 protocol-node:
+43
Documentation/devicetree/bindings/firmware/nxp,imx95-scmi.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + # Copyright 2024 NXP 3 + %YAML 1.2 4 + --- 5 + $id: http://devicetree.org/schemas/firmware/nxp,imx95-scmi.yaml# 6 + $schema: http://devicetree.org/meta-schemas/core.yaml# 7 + 8 + title: i.MX95 System Control and Management Interface(SCMI) Vendor Protocols Extension 9 + 10 + maintainers: 11 + - Peng Fan <peng.fan@nxp.com> 12 + 13 + properties: 14 + protocol@81: 15 + $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node' 16 + unevaluatedProperties: false 17 + 18 + properties: 19 + reg: 20 + const: 0x81 21 + 22 + protocol@84: 23 + $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node' 24 + unevaluatedProperties: false 25 + 26 + properties: 27 + reg: 28 + const: 0x84 29 + 30 + nxp,ctrl-ids: 31 + description: 32 + Each entry consists of 2 integers, represents the ctrl id and the value 33 + items: 34 + items: 35 + - description: the ctrl id index 36 + enum: [0, 1, 2, 3, 4, 5, 6, 7, 0x8000, 0x8001, 0x8002, 0x8003, 37 + 0x8004, 0x8005, 0x8006, 0x8007] 38 + - description: the value assigned to the ctrl id 39 + minItems: 1 40 + maxItems: 16 41 + $ref: /schemas/types.yaml#/definitions/uint32-matrix 42 + 43 + additionalProperties: true
+13 -107
drivers/firmware/arm_scmi/Kconfig
··· 55 55 operate normally, thing which could make an SCMI test suite using the 56 56 SCMI Raw mode support unreliable. If unsure, say N. 57 57 58 - config ARM_SCMI_HAVE_TRANSPORT 59 - bool 58 + config ARM_SCMI_DEBUG_COUNTERS 59 + bool "Enable SCMI communication debug metrics tracking" 60 + select ARM_SCMI_NEED_DEBUGFS 61 + depends on DEBUG_FS 62 + default n 60 63 help 61 - This declares whether at least one SCMI transport has been configured. 62 - Used to trigger a build bug when trying to build SCMI without any 63 - configured transport. 64 + Enables tracking of some key communication metrics for debug 65 + purposes. It may track metrics like how many messages were sent 66 + or received, were there any failures, what kind of failures, ..etc. 64 67 65 - config ARM_SCMI_HAVE_SHMEM 66 - bool 67 - help 68 - This declares whether a shared memory based transport for SCMI is 69 - available. 68 + Enable this option to create a new debugfs directory which contains 69 + such useful debug counters. This can be helpful for debugging and 70 + SCMI monitoring. 70 71 71 - config ARM_SCMI_HAVE_MSG 72 - bool 73 - help 74 - This declares whether a message passing based transport for SCMI is 75 - available. 76 - 77 - config ARM_SCMI_TRANSPORT_MAILBOX 78 - bool "SCMI transport based on Mailbox" 79 - depends on MAILBOX 80 - select ARM_SCMI_HAVE_TRANSPORT 81 - select ARM_SCMI_HAVE_SHMEM 82 - default y 83 - help 84 - Enable mailbox based transport for SCMI. 85 - 86 - If you want the ARM SCMI PROTOCOL stack to include support for a 87 - transport based on mailboxes, answer Y. 88 - 89 - config ARM_SCMI_TRANSPORT_OPTEE 90 - bool "SCMI transport based on OP-TEE service" 91 - depends on OPTEE=y || OPTEE=ARM_SCMI_PROTOCOL 92 - select ARM_SCMI_HAVE_TRANSPORT 93 - select ARM_SCMI_HAVE_SHMEM 94 - select ARM_SCMI_HAVE_MSG 95 - default y 96 - help 97 - This enables the OP-TEE service based transport for SCMI. 98 - 99 - If you want the ARM SCMI PROTOCOL stack to include support for a 100 - transport based on OP-TEE SCMI service, answer Y. 101 - 102 - config ARM_SCMI_TRANSPORT_SMC 103 - bool "SCMI transport based on SMC" 104 - depends on HAVE_ARM_SMCCC_DISCOVERY 105 - select ARM_SCMI_HAVE_TRANSPORT 106 - select ARM_SCMI_HAVE_SHMEM 107 - default y 108 - help 109 - Enable SMC based transport for SCMI. 110 - 111 - If you want the ARM SCMI PROTOCOL stack to include support for a 112 - transport based on SMC, answer Y. 113 - 114 - config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE 115 - bool "Enable atomic mode support for SCMI SMC transport" 116 - depends on ARM_SCMI_TRANSPORT_SMC 117 - help 118 - Enable support of atomic operation for SCMI SMC based transport. 119 - 120 - If you want the SCMI SMC based transport to operate in atomic 121 - mode, avoiding any kind of sleeping behaviour for selected 122 - transactions on the TX path, answer Y. 123 - Enabling atomic mode operations allows any SCMI driver using this 124 - transport to optionally ask for atomic SCMI transactions and operate 125 - in atomic context too, at the price of using a number of busy-waiting 126 - primitives all over instead. If unsure say N. 127 - 128 - config ARM_SCMI_TRANSPORT_VIRTIO 129 - bool "SCMI transport based on VirtIO" 130 - depends on VIRTIO=y || VIRTIO=ARM_SCMI_PROTOCOL 131 - select ARM_SCMI_HAVE_TRANSPORT 132 - select ARM_SCMI_HAVE_MSG 133 - help 134 - This enables the virtio based transport for SCMI. 135 - 136 - If you want the ARM SCMI PROTOCOL stack to include support for a 137 - transport based on VirtIO, answer Y. 138 - 139 - config ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE 140 - bool "SCMI VirtIO transport Version 1 compliance" 141 - depends on ARM_SCMI_TRANSPORT_VIRTIO 142 - default y 143 - help 144 - This enforces strict compliance with VirtIO Version 1 specification. 145 - 146 - If you want the ARM SCMI VirtIO transport layer to refuse to work 147 - with Legacy VirtIO backends and instead support only VirtIO Version 1 148 - devices (or above), answer Y. 149 - 150 - If you want instead to support also old Legacy VirtIO backends (like 151 - the ones implemented by kvmtool) and let the core Kernel VirtIO layer 152 - take care of the needed conversions, say N. 153 - 154 - config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE 155 - bool "Enable atomic mode for SCMI VirtIO transport" 156 - depends on ARM_SCMI_TRANSPORT_VIRTIO 157 - help 158 - Enable support of atomic operation for SCMI VirtIO based transport. 159 - 160 - If you want the SCMI VirtIO based transport to operate in atomic 161 - mode, avoiding any kind of sleeping behaviour for selected 162 - transactions on the TX path, answer Y. 163 - 164 - Enabling atomic mode operations allows any SCMI driver using this 165 - transport to optionally ask for atomic SCMI transactions and operate 166 - in atomic context too, at the price of using a number of busy-waiting 167 - primitives all over instead. If unsure say N. 72 + source "drivers/firmware/arm_scmi/transports/Kconfig" 73 + source "drivers/firmware/arm_scmi/vendors/imx/Kconfig" 168 74 169 75 endif #ARM_SCMI_PROTOCOL 170 76
+3 -11
drivers/firmware/arm_scmi/Makefile
··· 5 5 scmi-driver-y = driver.o notify.o 6 6 scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o 7 7 scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o 8 - scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o 9 - scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o 10 8 scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o 11 - scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o 12 - scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o 13 9 scmi-protocols-y := base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o 14 10 scmi-protocols-y += pinctrl.o 15 11 scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) 12 + 13 + obj-$(CONFIG_ARM_SCMI_PROTOCOL) += transports/ 14 + obj-$(CONFIG_ARM_SCMI_PROTOCOL) += vendors/imx/ 16 15 17 16 obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o 18 17 obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o 19 18 20 19 obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o 21 - 22 - ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) 23 - # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame 24 - # pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling 25 - # hooks are inserted via the -pg switch. 26 - CFLAGS_REMOVE_smc.o += $(CC_FLAGS_FTRACE) 27 - endif
+2 -4
drivers/firmware/arm_scmi/base.c
··· 14 14 #include "notify.h" 15 15 16 16 /* Updated only after ALL the mandatory features for that version are merged */ 17 - #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 17 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 18 18 19 19 #define SCMI_BASE_NUM_SOURCES 1 20 20 #define SCMI_BASE_MAX_CMD_ERR_COUNT 1024 ··· 41 41 __le32 agent_id; 42 42 u8 name[SCMI_SHORT_NAME_MAX_SIZE]; 43 43 }; 44 - 45 44 46 45 struct scmi_msg_base_error_notify { 47 46 __le32 event_control; ··· 103 104 char *vendor_id; 104 105 struct scmi_xfer *t; 105 106 struct scmi_revision_info *rev = ph->get_priv(ph); 106 - 107 107 108 108 if (sub_vendor) { 109 109 cmd = BASE_DISCOVER_SUB_VENDOR; ··· 384 386 if (ret) 385 387 return ret; 386 388 387 - rev->major_ver = PROTOCOL_REV_MAJOR(version), 389 + rev->major_ver = PROTOCOL_REV_MAJOR(version); 388 390 rev->minor_ver = PROTOCOL_REV_MINOR(version); 389 391 ph->set_priv(ph, rev, version); 390 392
+1
drivers/firmware/arm_scmi/clock.c
··· 365 365 ret = ph->xops->do_xfer(ph, t); 366 366 if (!ret) { 367 367 u32 latency = 0; 368 + 368 369 attributes = le32_to_cpu(attr->attributes); 369 370 strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE); 370 371 /* clock_enable_latency field is present only since SCMI v3.1 */
+160 -46
drivers/firmware/arm_scmi/common.h
··· 4 4 * driver common header file containing some definitions, structures 5 5 * and function prototypes used in all the different SCMI protocols. 6 6 * 7 - * Copyright (C) 2018-2022 ARM Ltd. 7 + * Copyright (C) 2018-2024 ARM Ltd. 8 8 */ 9 9 #ifndef _SCMI_COMMON_H 10 10 #define _SCMI_COMMON_H ··· 183 183 /** 184 184 * struct scmi_transport_ops - Structure representing a SCMI transport ops 185 185 * 186 - * @link_supplier: Optional callback to add link to a supplier device 187 186 * @chan_available: Callback to check if channel is available or not 188 187 * @chan_setup: Callback to allocate and setup a channel 189 188 * @chan_free: Callback to free a channel ··· 197 198 * @poll_done: Callback to poll transfer status 198 199 */ 199 200 struct scmi_transport_ops { 200 - int (*link_supplier)(struct device *dev); 201 201 bool (*chan_available)(struct device_node *of_node, int idx); 202 202 int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev, 203 203 bool tx); ··· 217 219 /** 218 220 * struct scmi_desc - Description of SoC integration 219 221 * 220 - * @transport_init: An optional function that a transport can provide to 221 - * initialize some transport-specific setup during SCMI core 222 - * initialization, so ahead of SCMI core probing. 223 - * @transport_exit: An optional function that a transport can provide to 224 - * de-initialize some transport-specific setup during SCMI core 225 - * de-initialization, so after SCMI core removal. 226 222 * @ops: Pointer to the transport specific ops structure 227 223 * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds) 228 224 * @max_msg: Maximum number of messages for a channel type (tx or rx) that can ··· 237 245 * when requested. 238 246 */ 239 247 struct scmi_desc { 240 - int (*transport_init)(void); 241 - void (*transport_exit)(void); 242 248 const struct scmi_transport_ops *ops; 243 249 int max_rx_timeout_ms; 244 250 int max_msg; ··· 276 286 int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo, 277 287 struct scmi_xfer *xfer, 278 288 unsigned int timeout_ms); 279 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX 280 - extern const struct scmi_desc scmi_mailbox_desc; 281 - #endif 282 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC 283 - extern const struct scmi_desc scmi_smc_desc; 284 - #endif 285 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO 286 - extern const struct scmi_desc scmi_virtio_desc; 287 - #endif 288 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE 289 - extern const struct scmi_desc scmi_optee_desc; 290 - #endif 291 289 292 - void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); 290 + enum debug_counters { 291 + SENT_OK, 292 + SENT_FAIL, 293 + SENT_FAIL_POLLING_UNSUPPORTED, 294 + SENT_FAIL_CHANNEL_NOT_FOUND, 295 + RESPONSE_OK, 296 + NOTIFICATION_OK, 297 + DELAYED_RESPONSE_OK, 298 + XFERS_RESPONSE_TIMEOUT, 299 + XFERS_RESPONSE_POLLED_TIMEOUT, 300 + RESPONSE_POLLED_OK, 301 + ERR_MSG_UNEXPECTED, 302 + ERR_MSG_INVALID, 303 + ERR_MSG_NOMEM, 304 + ERR_PROTOCOL, 305 + SCMI_DEBUG_COUNTERS_LAST 306 + }; 307 + 308 + static inline void scmi_inc_count(atomic_t *arr, int stat) 309 + { 310 + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) 311 + atomic_inc(&arr[stat]); 312 + } 293 313 294 314 enum scmi_bad_msg { 295 315 MSG_UNEXPECTED = -1, ··· 309 309 MSG_MBOX_SPURIOUS = -5, 310 310 }; 311 311 312 - void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, 313 - enum scmi_bad_msg err); 314 - 315 312 /* shmem related declarations */ 316 313 struct scmi_shared_mem; 317 314 318 - void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, 319 - struct scmi_xfer *xfer, struct scmi_chan_info *cinfo); 320 - u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem); 321 - void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, 315 + /** 316 + * struct scmi_shared_mem_operations - Transport core operations for 317 + * Shared Memory 318 + * 319 + * @tx_prepare: Prepare the @xfer message for transmission on the chosen @shmem 320 + * @read_header: Read header of the message currently hold in @shmem 321 + * @fetch_response: Copy the message response from @shmem into @xfer 322 + * @fetch_notification: Copy the message notification from @shmem into @xfer 323 + * @clear_channel: Clear the @shmem channel busy flag 324 + * @poll_done: Check if poll has completed for @xfer on @shmem 325 + * @channel_free: Check if @shmem channel is marked as free 326 + * @channel_intr_enabled: Check is @shmem channel has requested a completion irq 327 + * @setup_iomap: Setup IO shared memory for channel @cinfo 328 + */ 329 + struct scmi_shared_mem_operations { 330 + void (*tx_prepare)(struct scmi_shared_mem __iomem *shmem, 331 + struct scmi_xfer *xfer, 332 + struct scmi_chan_info *cinfo); 333 + u32 (*read_header)(struct scmi_shared_mem __iomem *shmem); 334 + 335 + void (*fetch_response)(struct scmi_shared_mem __iomem *shmem, 336 + struct scmi_xfer *xfer); 337 + void (*fetch_notification)(struct scmi_shared_mem __iomem *shmem, 338 + size_t max_len, struct scmi_xfer *xfer); 339 + void (*clear_channel)(struct scmi_shared_mem __iomem *shmem); 340 + bool (*poll_done)(struct scmi_shared_mem __iomem *shmem, 322 341 struct scmi_xfer *xfer); 323 - void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, 324 - size_t max_len, struct scmi_xfer *xfer); 325 - void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); 326 - bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, 327 - struct scmi_xfer *xfer); 328 - bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); 329 - bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem); 342 + bool (*channel_free)(struct scmi_shared_mem __iomem *shmem); 343 + bool (*channel_intr_enabled)(struct scmi_shared_mem __iomem *shmem); 344 + void __iomem *(*setup_iomap)(struct scmi_chan_info *cinfo, 345 + struct device *dev, 346 + bool tx, struct resource *res); 347 + }; 348 + 349 + const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void); 330 350 331 351 /* declarations for message passing transports */ 332 352 struct scmi_msg_payld; ··· 354 334 /* Maximum overhead of message w.r.t. struct scmi_desc.max_msg_size */ 355 335 #define SCMI_MSG_MAX_PROT_OVERHEAD (2 * sizeof(__le32)) 356 336 357 - size_t msg_response_size(struct scmi_xfer *xfer); 358 - size_t msg_command_size(struct scmi_xfer *xfer); 359 - void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer); 360 - u32 msg_read_header(struct scmi_msg_payld *msg); 361 - void msg_fetch_response(struct scmi_msg_payld *msg, size_t len, 362 - struct scmi_xfer *xfer); 363 - void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, 364 - size_t max_len, struct scmi_xfer *xfer); 337 + /** 338 + * struct scmi_message_operations - Transport core operations for Message 339 + * 340 + * @response_size: Get calculated response size for @xfer 341 + * @command_size: Get calculated command size for @xfer 342 + * @tx_prepare: Prepare the @xfer message for transmission on the provided @msg 343 + * @read_header: Read header of the message currently hold in @msg 344 + * @fetch_response: Copy the message response from @msg into @xfer 345 + * @fetch_notification: Copy the message notification from @msg into @xfer 346 + */ 347 + struct scmi_message_operations { 348 + size_t (*response_size)(struct scmi_xfer *xfer); 349 + size_t (*command_size)(struct scmi_xfer *xfer); 350 + void (*tx_prepare)(struct scmi_msg_payld *msg, struct scmi_xfer *xfer); 351 + u32 (*read_header)(struct scmi_msg_payld *msg); 352 + void (*fetch_response)(struct scmi_msg_payld *msg, size_t len, 353 + struct scmi_xfer *xfer); 354 + void (*fetch_notification)(struct scmi_msg_payld *msg, size_t len, 355 + size_t max_len, struct scmi_xfer *xfer); 356 + }; 357 + 358 + const struct scmi_message_operations *scmi_message_operations_get(void); 359 + 360 + /** 361 + * struct scmi_transport_core_operations - Transpoert core operations 362 + * 363 + * @bad_message_trace: An helper to report a malformed/unexpected message 364 + * @rx_callback: Callback to report received messages 365 + * @shmem: Datagram operations for shared memory based transports 366 + * @msg: Datagram operations for message based transports 367 + */ 368 + struct scmi_transport_core_operations { 369 + void (*bad_message_trace)(struct scmi_chan_info *cinfo, 370 + u32 msg_hdr, enum scmi_bad_msg err); 371 + void (*rx_callback)(struct scmi_chan_info *cinfo, u32 msg_hdr, 372 + void *priv); 373 + const struct scmi_shared_mem_operations *shmem; 374 + const struct scmi_message_operations *msg; 375 + }; 376 + 377 + /** 378 + * struct scmi_transport - A structure representing a configured transport 379 + * 380 + * @supplier: Device representing the transport and acting as a supplier for 381 + * the core SCMI stack 382 + * @desc: Transport descriptor 383 + * @core_ops: A pointer to a pointer used by the core SCMI stack to make the 384 + * core transport operations accessible to the transports. 385 + */ 386 + struct scmi_transport { 387 + struct device *supplier; 388 + struct scmi_desc *desc; 389 + struct scmi_transport_core_operations **core_ops; 390 + }; 391 + 392 + #define DEFINE_SCMI_TRANSPORT_DRIVER(__tag, __drv, __desc, __match, __core_ops)\ 393 + static void __tag##_dev_free(void *data) \ 394 + { \ 395 + struct platform_device *spdev = data; \ 396 + \ 397 + platform_device_unregister(spdev); \ 398 + } \ 399 + \ 400 + static int __tag##_probe(struct platform_device *pdev) \ 401 + { \ 402 + struct device *dev = &pdev->dev; \ 403 + struct platform_device *spdev; \ 404 + struct scmi_transport strans; \ 405 + int ret; \ 406 + \ 407 + spdev = platform_device_alloc("arm-scmi", PLATFORM_DEVID_AUTO); \ 408 + if (!spdev) \ 409 + return -ENOMEM; \ 410 + \ 411 + device_set_of_node_from_dev(&spdev->dev, dev); \ 412 + \ 413 + strans.supplier = dev; \ 414 + strans.desc = &(__desc); \ 415 + strans.core_ops = &(__core_ops); \ 416 + \ 417 + ret = platform_device_add_data(spdev, &strans, sizeof(strans)); \ 418 + if (ret) \ 419 + goto err; \ 420 + \ 421 + ret = platform_device_add(spdev); \ 422 + if (ret) \ 423 + goto err; \ 424 + \ 425 + return devm_add_action_or_reset(dev, __tag##_dev_free, spdev); \ 426 + \ 427 + err: \ 428 + platform_device_put(spdev); \ 429 + return ret; \ 430 + } \ 431 + \ 432 + static struct platform_driver __drv = { \ 433 + .driver = { \ 434 + .name = #__tag "_transport", \ 435 + .of_match_table = __match, \ 436 + }, \ 437 + .probe = __tag##_probe, \ 438 + } 365 439 366 440 void scmi_notification_instance_data_set(const struct scmi_handle *handle, 367 441 void *priv);
+135 -106
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-2021 ARM Ltd. 14 + * Copyright (C) 2018-2024 ARM Ltd. 15 15 */ 16 16 17 17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ··· 117 117 * @name: Name of this SCMI instance 118 118 * @type: Type of this SCMI instance 119 119 * @is_atomic: Flag to state if the transport of this instance is atomic 120 + * @counters: An array of atomic_c's used for tracking statistics (if enabled) 120 121 */ 121 122 struct scmi_debug_info { 122 123 struct dentry *top_dentry; 123 124 const char *name; 124 125 const char *type; 125 126 bool is_atomic; 127 + atomic_t counters[SCMI_DEBUG_COUNTERS_LAST]; 126 128 }; 127 129 128 130 /** ··· 195 193 #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) 196 194 #define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb) 197 195 #define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb) 196 + 197 + static void scmi_rx_callback(struct scmi_chan_info *cinfo, 198 + u32 msg_hdr, void *priv); 199 + static void scmi_bad_message_trace(struct scmi_chan_info *cinfo, 200 + u32 msg_hdr, enum scmi_bad_msg err); 201 + 202 + static struct scmi_transport_core_operations scmi_trans_core_ops = { 203 + .bad_message_trace = scmi_bad_message_trace, 204 + .rx_callback = scmi_rx_callback, 205 + }; 198 206 199 207 static unsigned long 200 208 scmi_vendor_protocol_signature(unsigned int protocol_id, char *vendor_id, ··· 845 833 * timed-out message that arrives and as such, can be traced only referring to 846 834 * the header content, since the payload is missing/unreliable. 847 835 */ 848 - void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, 849 - enum scmi_bad_msg err) 836 + static void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, 837 + enum scmi_bad_msg err) 850 838 { 851 839 char *tag; 852 840 struct scmi_info *info = handle_to_scmi_info(cinfo->handle); ··· 1000 988 spin_unlock_irqrestore(&minfo->xfer_lock, flags); 1001 989 1002 990 scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNEXPECTED); 991 + scmi_inc_count(info->dbg->counters, ERR_MSG_UNEXPECTED); 1003 992 1004 993 return xfer; 1005 994 } ··· 1028 1015 msg_type, xfer_id, msg_hdr, xfer->state); 1029 1016 1030 1017 scmi_bad_message_trace(cinfo, msg_hdr, MSG_INVALID); 1018 + scmi_inc_count(info->dbg->counters, ERR_MSG_INVALID); 1031 1019 1032 1020 /* On error the refcount incremented above has to be dropped */ 1033 1021 __scmi_xfer_put(minfo, xfer); ··· 1068 1054 PTR_ERR(xfer)); 1069 1055 1070 1056 scmi_bad_message_trace(cinfo, msg_hdr, MSG_NOMEM); 1057 + scmi_inc_count(info->dbg->counters, ERR_MSG_NOMEM); 1071 1058 1072 1059 scmi_clear_channel(info, cinfo); 1073 1060 return; ··· 1084 1069 trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, 1085 1070 xfer->hdr.id, "NOTI", xfer->hdr.seq, 1086 1071 xfer->hdr.status, xfer->rx.buf, xfer->rx.len); 1072 + scmi_inc_count(info->dbg->counters, NOTIFICATION_OK); 1087 1073 1088 1074 scmi_notify(cinfo->handle, xfer->hdr.protocol_id, 1089 1075 xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts); ··· 1144 1128 if (xfer->hdr.type == MSG_TYPE_DELAYED_RESP) { 1145 1129 scmi_clear_channel(info, cinfo); 1146 1130 complete(xfer->async_done); 1131 + scmi_inc_count(info->dbg->counters, DELAYED_RESPONSE_OK); 1147 1132 } else { 1148 1133 complete(&xfer->done); 1134 + scmi_inc_count(info->dbg->counters, RESPONSE_OK); 1149 1135 } 1150 1136 1151 1137 if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { ··· 1178 1160 * NOTE: This function will be invoked in IRQ context, hence should be 1179 1161 * as optimal as possible. 1180 1162 */ 1181 - void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv) 1163 + static void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, 1164 + void *priv) 1182 1165 { 1183 1166 u8 msg_type = MSG_XTRACT_TYPE(msg_hdr); 1184 1167 ··· 1232 1213 struct scmi_xfer *xfer, unsigned int timeout_ms) 1233 1214 { 1234 1215 int ret = 0; 1216 + struct scmi_info *info = handle_to_scmi_info(cinfo->handle); 1235 1217 1236 1218 if (xfer->hdr.poll_completion) { 1237 1219 /* ··· 1253 1233 "timed out in resp(caller: %pS) - polling\n", 1254 1234 (void *)_RET_IP_); 1255 1235 ret = -ETIMEDOUT; 1236 + scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_POLLED_TIMEOUT); 1256 1237 } 1257 1238 } 1258 1239 1259 1240 if (!ret) { 1260 1241 unsigned long flags; 1261 - struct scmi_info *info = 1262 - handle_to_scmi_info(cinfo->handle); 1263 1242 1264 1243 /* 1265 1244 * Do not fetch_response if an out-of-order delayed ··· 1278 1259 "RESP" : "resp", 1279 1260 xfer->hdr.seq, xfer->hdr.status, 1280 1261 xfer->rx.buf, xfer->rx.len); 1262 + scmi_inc_count(info->dbg->counters, RESPONSE_POLLED_OK); 1281 1263 1282 1264 if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { 1283 - struct scmi_info *info = 1284 - handle_to_scmi_info(cinfo->handle); 1285 - 1286 1265 scmi_raw_message_report(info->raw, xfer, 1287 1266 SCMI_RAW_REPLY_QUEUE, 1288 1267 cinfo->id); ··· 1293 1276 dev_err(dev, "timed out in resp(caller: %pS)\n", 1294 1277 (void *)_RET_IP_); 1295 1278 ret = -ETIMEDOUT; 1279 + scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_TIMEOUT); 1296 1280 } 1297 1281 } 1298 1282 ··· 1377 1359 !is_transport_polling_capable(info->desc)) { 1378 1360 dev_warn_once(dev, 1379 1361 "Polling mode is not supported by transport.\n"); 1362 + scmi_inc_count(info->dbg->counters, SENT_FAIL_POLLING_UNSUPPORTED); 1380 1363 return -EINVAL; 1381 1364 } 1382 1365 1383 1366 cinfo = idr_find(&info->tx_idr, pi->proto->id); 1384 - if (unlikely(!cinfo)) 1367 + if (unlikely(!cinfo)) { 1368 + scmi_inc_count(info->dbg->counters, SENT_FAIL_CHANNEL_NOT_FOUND); 1385 1369 return -EINVAL; 1386 - 1370 + } 1387 1371 /* True ONLY if also supported by transport. */ 1388 1372 if (is_polling_enabled(cinfo, info->desc)) 1389 1373 xfer->hdr.poll_completion = true; ··· 1417 1397 ret = info->desc->ops->send_message(cinfo, xfer); 1418 1398 if (ret < 0) { 1419 1399 dev_dbg(dev, "Failed to send message %d\n", ret); 1400 + scmi_inc_count(info->dbg->counters, SENT_FAIL); 1420 1401 return ret; 1421 1402 } 1422 1403 1423 1404 trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, 1424 1405 xfer->hdr.id, "CMND", xfer->hdr.seq, 1425 1406 xfer->hdr.status, xfer->tx.buf, xfer->tx.len); 1407 + scmi_inc_count(info->dbg->counters, SENT_OK); 1426 1408 1427 1409 ret = scmi_wait_for_message_response(cinfo, xfer); 1428 - if (!ret && xfer->hdr.status) 1410 + if (!ret && xfer->hdr.status) { 1429 1411 ret = scmi_to_linux_errno(xfer->hdr.status); 1412 + scmi_inc_count(info->dbg->counters, ERR_PROTOCOL); 1413 + } 1430 1414 1431 1415 if (info->desc->ops->mark_txdone) 1432 1416 info->desc->ops->mark_txdone(cinfo, ret, xfer); ··· 2732 2708 static int scmi_channels_setup(struct scmi_info *info) 2733 2709 { 2734 2710 int ret; 2735 - struct device_node *child, *top_np = info->dev->of_node; 2711 + struct device_node *top_np = info->dev->of_node; 2736 2712 2737 2713 /* Initialize a common generic channel at first */ 2738 2714 ret = scmi_txrx_setup(info, top_np, SCMI_PROTOCOL_BASE); 2739 2715 if (ret) 2740 2716 return ret; 2741 2717 2742 - for_each_available_child_of_node(top_np, child) { 2718 + for_each_available_child_of_node_scoped(top_np, child) { 2743 2719 u32 prot_id; 2744 2720 2745 2721 if (of_property_read_u32(child, "reg", &prot_id)) ··· 2750 2726 "Out of range protocol %d\n", prot_id); 2751 2727 2752 2728 ret = scmi_txrx_setup(info, child, prot_id); 2753 - if (ret) { 2754 - of_node_put(child); 2729 + if (ret) 2755 2730 return ret; 2756 - } 2757 2731 } 2758 2732 2759 2733 return 0; ··· 2855 2833 return NOTIFY_OK; 2856 2834 } 2857 2835 2836 + static const char * const dbg_counter_strs[] = { 2837 + "sent_ok", 2838 + "sent_fail", 2839 + "sent_fail_polling_unsupported", 2840 + "sent_fail_channel_not_found", 2841 + "response_ok", 2842 + "notification_ok", 2843 + "delayed_response_ok", 2844 + "xfers_response_timeout", 2845 + "xfers_response_polled_timeout", 2846 + "response_polled_ok", 2847 + "err_msg_unexpected", 2848 + "err_msg_invalid", 2849 + "err_msg_nomem", 2850 + "err_protocol", 2851 + }; 2852 + 2853 + static ssize_t reset_all_on_write(struct file *filp, const char __user *buf, 2854 + size_t count, loff_t *ppos) 2855 + { 2856 + struct scmi_debug_info *dbg = filp->private_data; 2857 + 2858 + for (int i = 0; i < SCMI_DEBUG_COUNTERS_LAST; i++) 2859 + atomic_set(&dbg->counters[i], 0); 2860 + 2861 + return count; 2862 + } 2863 + 2864 + static const struct file_operations fops_reset_counts = { 2865 + .owner = THIS_MODULE, 2866 + .open = simple_open, 2867 + .llseek = no_llseek, 2868 + .write = reset_all_on_write, 2869 + }; 2870 + 2871 + static void scmi_debugfs_counters_setup(struct scmi_debug_info *dbg, 2872 + struct dentry *trans) 2873 + { 2874 + struct dentry *counters; 2875 + int idx; 2876 + 2877 + counters = debugfs_create_dir("counters", trans); 2878 + 2879 + for (idx = 0; idx < SCMI_DEBUG_COUNTERS_LAST; idx++) 2880 + debugfs_create_atomic_t(dbg_counter_strs[idx], 0600, counters, 2881 + &dbg->counters[idx]); 2882 + 2883 + debugfs_create_file("reset", 0200, counters, dbg, &fops_reset_counts); 2884 + } 2885 + 2858 2886 static void scmi_debugfs_common_cleanup(void *d) 2859 2887 { 2860 2888 struct scmi_debug_info *dbg = d; ··· 2971 2899 debugfs_create_u32("rx_max_msg", 0400, trans, 2972 2900 (u32 *)&info->rx_minfo.max_msg); 2973 2901 2902 + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) 2903 + scmi_debugfs_counters_setup(dbg, trans); 2904 + 2974 2905 dbg->top_dentry = top_dentry; 2975 2906 2976 2907 if (devm_add_action_or_reset(info->dev, ··· 3025 2950 return ret; 3026 2951 } 3027 2952 2953 + static const struct scmi_desc *scmi_transport_setup(struct device *dev) 2954 + { 2955 + struct scmi_transport *trans; 2956 + int ret; 2957 + 2958 + trans = dev_get_platdata(dev); 2959 + if (!trans || !trans->desc || !trans->supplier || !trans->core_ops) 2960 + return NULL; 2961 + 2962 + if (!device_link_add(dev, trans->supplier, DL_FLAG_AUTOREMOVE_CONSUMER)) { 2963 + dev_err(dev, 2964 + "Adding link to supplier transport device failed\n"); 2965 + return NULL; 2966 + } 2967 + 2968 + /* Provide core transport ops */ 2969 + *trans->core_ops = &scmi_trans_core_ops; 2970 + 2971 + dev_info(dev, "Using %s\n", dev_driver_string(trans->supplier)); 2972 + 2973 + ret = of_property_read_u32(dev->of_node, "max-rx-timeout-ms", 2974 + &trans->desc->max_rx_timeout_ms); 2975 + if (ret && ret != -EINVAL) 2976 + dev_err(dev, "Malformed max-rx-timeout-ms DT property.\n"); 2977 + 2978 + dev_info(dev, "SCMI max-rx-timeout: %dms\n", 2979 + trans->desc->max_rx_timeout_ms); 2980 + 2981 + return trans->desc; 2982 + } 2983 + 3028 2984 static int scmi_probe(struct platform_device *pdev) 3029 2985 { 3030 2986 int ret; ··· 3067 2961 struct device *dev = &pdev->dev; 3068 2962 struct device_node *child, *np = dev->of_node; 3069 2963 3070 - desc = of_device_get_match_data(dev); 3071 - if (!desc) 3072 - return -EINVAL; 2964 + desc = scmi_transport_setup(dev); 2965 + if (!desc) { 2966 + err_str = "transport invalid\n"; 2967 + ret = -EINVAL; 2968 + goto out_err; 2969 + } 3073 2970 3074 2971 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); 3075 2972 if (!info) ··· 3110 3001 "SCMI System wide atomic threshold set to %d us\n", 3111 3002 info->atomic_threshold); 3112 3003 handle->is_transport_atomic = scmi_is_transport_atomic; 3113 - 3114 - if (desc->ops->link_supplier) { 3115 - ret = desc->ops->link_supplier(dev); 3116 - if (ret) { 3117 - err_str = "transport not ready\n"; 3118 - goto clear_ida; 3119 - } 3120 - } 3121 3004 3122 3005 /* Setup all channels described in the DT at first */ 3123 3006 ret = scmi_channels_setup(info); ··· 3231 3130 clear_ida: 3232 3131 ida_free(&scmi_id, info->id); 3233 3132 3133 + out_err: 3234 3134 return dev_err_probe(dev, ret, "%s", err_str); 3235 3135 } 3236 3136 ··· 3317 3215 }; 3318 3216 ATTRIBUTE_GROUPS(versions); 3319 3217 3320 - /* Each compatible listed below must have descriptor associated with it */ 3321 - static const struct of_device_id scmi_of_match[] = { 3322 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX 3323 - { .compatible = "arm,scmi", .data = &scmi_mailbox_desc }, 3324 - #endif 3325 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE 3326 - { .compatible = "linaro,scmi-optee", .data = &scmi_optee_desc }, 3327 - #endif 3328 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC 3329 - { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, 3330 - { .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc}, 3331 - { .compatible = "qcom,scmi-smc", .data = &scmi_smc_desc}, 3332 - #endif 3333 - #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO 3334 - { .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc}, 3335 - #endif 3336 - { /* Sentinel */ }, 3337 - }; 3338 - 3339 - MODULE_DEVICE_TABLE(of, scmi_of_match); 3340 - 3341 3218 static struct platform_driver scmi_driver = { 3342 3219 .driver = { 3343 3220 .name = "arm-scmi", 3344 3221 .suppress_bind_attrs = true, 3345 - .of_match_table = scmi_of_match, 3346 3222 .dev_groups = versions_groups, 3347 3223 }, 3348 3224 .probe = scmi_probe, 3349 3225 .remove_new = scmi_remove, 3350 3226 }; 3351 - 3352 - /** 3353 - * __scmi_transports_setup - Common helper to call transport-specific 3354 - * .init/.exit code if provided. 3355 - * 3356 - * @init: A flag to distinguish between init and exit. 3357 - * 3358 - * Note that, if provided, we invoke .init/.exit functions for all the 3359 - * transports currently compiled in. 3360 - * 3361 - * Return: 0 on Success. 3362 - */ 3363 - static inline int __scmi_transports_setup(bool init) 3364 - { 3365 - int ret = 0; 3366 - const struct of_device_id *trans; 3367 - 3368 - for (trans = scmi_of_match; trans->data; trans++) { 3369 - const struct scmi_desc *tdesc = trans->data; 3370 - 3371 - if ((init && !tdesc->transport_init) || 3372 - (!init && !tdesc->transport_exit)) 3373 - continue; 3374 - 3375 - if (init) 3376 - ret = tdesc->transport_init(); 3377 - else 3378 - tdesc->transport_exit(); 3379 - 3380 - if (ret) { 3381 - pr_err("SCMI transport %s FAILED initialization!\n", 3382 - trans->compatible); 3383 - break; 3384 - } 3385 - } 3386 - 3387 - return ret; 3388 - } 3389 - 3390 - static int __init scmi_transports_init(void) 3391 - { 3392 - return __scmi_transports_setup(true); 3393 - } 3394 - 3395 - static void __exit scmi_transports_exit(void) 3396 - { 3397 - __scmi_transports_setup(false); 3398 - } 3399 3227 3400 3228 static struct dentry *scmi_debugfs_init(void) 3401 3229 { ··· 3342 3310 3343 3311 static int __init scmi_driver_init(void) 3344 3312 { 3345 - int ret; 3346 - 3347 3313 /* Bail out if no SCMI transport was configured */ 3348 3314 if (WARN_ON(!IS_ENABLED(CONFIG_ARM_SCMI_HAVE_TRANSPORT))) 3349 3315 return -EINVAL; 3350 3316 3351 - /* Initialize any compiled-in transport which provided an init/exit */ 3352 - ret = scmi_transports_init(); 3353 - if (ret) 3354 - return ret; 3317 + if (IS_ENABLED(CONFIG_ARM_SCMI_HAVE_SHMEM)) 3318 + scmi_trans_core_ops.shmem = scmi_shared_mem_operations_get(); 3319 + 3320 + if (IS_ENABLED(CONFIG_ARM_SCMI_HAVE_MSG)) 3321 + scmi_trans_core_ops.msg = scmi_message_operations_get(); 3355 3322 3356 3323 if (IS_ENABLED(CONFIG_ARM_SCMI_NEED_DEBUGFS)) 3357 3324 scmi_top_dentry = scmi_debugfs_init(); ··· 3384 3353 scmi_system_unregister(); 3385 3354 scmi_powercap_unregister(); 3386 3355 scmi_pinctrl_unregister(); 3387 - 3388 - scmi_transports_exit(); 3389 3356 3390 3357 platform_driver_unregister(&scmi_driver); 3391 3358
+40 -44
drivers/firmware/arm_scmi/mailbox.c drivers/firmware/arm_scmi/transports/mailbox.c
··· 3 3 * System Control and Management Interface (SCMI) Message Mailbox Transport 4 4 * driver. 5 5 * 6 - * Copyright (C) 2019 ARM Ltd. 6 + * Copyright (C) 2019-2024 ARM Ltd. 7 7 */ 8 8 9 9 #include <linux/err.h> ··· 11 11 #include <linux/mailbox_client.h> 12 12 #include <linux/of.h> 13 13 #include <linux/of_address.h> 14 + #include <linux/platform_device.h> 14 15 #include <linux/slab.h> 15 16 16 - #include "common.h" 17 + #include "../common.h" 17 18 18 19 /** 19 20 * struct scmi_mailbox - Structure representing a SCMI mailbox transport ··· 37 36 38 37 #define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl) 39 38 39 + static struct scmi_transport_core_operations *core; 40 + 40 41 static void tx_prepare(struct mbox_client *cl, void *m) 41 42 { 42 43 struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); 43 44 44 - shmem_tx_prepare(smbox->shmem, m, smbox->cinfo); 45 + core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo); 45 46 } 46 47 47 48 static void rx_callback(struct mbox_client *cl, void *m) ··· 59 56 * a previous timed-out reply which arrived late could be wrongly 60 57 * associated with the next pending transaction. 61 58 */ 62 - if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { 59 + if (cl->knows_txdone && 60 + !core->shmem->channel_free(smbox->shmem)) { 63 61 dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); 64 - scmi_bad_message_trace(smbox->cinfo, 65 - shmem_read_header(smbox->shmem), 66 - MSG_MBOX_SPURIOUS); 62 + core->bad_message_trace(smbox->cinfo, 63 + core->shmem->read_header(smbox->shmem), 64 + MSG_MBOX_SPURIOUS); 67 65 return; 68 66 } 69 67 70 - scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); 68 + core->rx_callback(smbox->cinfo, 69 + core->shmem->read_header(smbox->shmem), NULL); 71 70 } 72 71 73 72 static bool mailbox_chan_available(struct device_node *of_node, int idx) ··· 129 124 130 125 /* Bail out if provided shmem descriptors do not refer distinct areas */ 131 126 if (num_sh > 1) { 132 - struct device_node *np_tx, *np_rx; 127 + struct device_node *np_tx __free(device_node) = 128 + of_parse_phandle(np, "shmem", 0); 129 + struct device_node *np_rx __free(device_node) = 130 + of_parse_phandle(np, "shmem", 1); 133 131 134 - np_tx = of_parse_phandle(np, "shmem", 0); 135 - np_rx = of_parse_phandle(np, "shmem", 1); 136 132 if (!np_tx || !np_rx || np_tx == np_rx) { 137 133 dev_warn(cdev, "Invalid shmem descriptor for '%s'\n", 138 134 of_node_full_name(np)); 139 135 ret = -EINVAL; 140 136 } 141 - 142 - of_node_put(np_tx); 143 - of_node_put(np_rx); 144 137 } 145 138 146 139 /* Calculate channels IDs to use depending on mboxes/shmem layout */ ··· 181 178 const char *desc = tx ? "Tx" : "Rx"; 182 179 struct device *cdev = cinfo->dev; 183 180 struct scmi_mailbox *smbox; 184 - struct device_node *shmem; 185 - int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan, idx = tx ? 0 : 1; 181 + int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan; 186 182 struct mbox_client *cl; 187 - resource_size_t size; 188 - struct resource res; 189 183 190 184 ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan, &p2a_rx_chan); 191 185 if (ret) ··· 195 195 if (!smbox) 196 196 return -ENOMEM; 197 197 198 - shmem = of_parse_phandle(cdev->of_node, "shmem", idx); 199 - if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) { 200 - of_node_put(shmem); 201 - return -ENXIO; 202 - } 203 - 204 - ret = of_address_to_resource(shmem, 0, &res); 205 - of_node_put(shmem); 206 - if (ret) { 207 - dev_err(cdev, "failed to get SCMI %s shared memory\n", desc); 208 - return ret; 209 - } 210 - 211 - size = resource_size(&res); 212 - smbox->shmem = devm_ioremap(dev, res.start, size); 213 - if (!smbox->shmem) { 214 - dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc); 215 - return -EADDRNOTAVAIL; 216 - } 198 + smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL); 199 + if (IS_ERR(smbox->shmem)) 200 + return PTR_ERR(smbox->shmem); 217 201 218 202 cl = &smbox->cl; 219 203 cl->dev = cdev; ··· 235 251 return ret; 236 252 } 237 253 } 238 - 239 254 240 255 cinfo->transport_info = smbox; 241 256 smbox->cinfo = cinfo; ··· 295 312 { 296 313 struct scmi_mailbox *smbox = cinfo->transport_info; 297 314 298 - shmem_fetch_response(smbox->shmem, xfer); 315 + core->shmem->fetch_response(smbox->shmem, xfer); 299 316 } 300 317 301 318 static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, ··· 303 320 { 304 321 struct scmi_mailbox *smbox = cinfo->transport_info; 305 322 306 - shmem_fetch_notification(smbox->shmem, max_len, xfer); 323 + core->shmem->fetch_notification(smbox->shmem, max_len, xfer); 307 324 } 308 325 309 326 static void mailbox_clear_channel(struct scmi_chan_info *cinfo) ··· 312 329 struct mbox_chan *intr_chan; 313 330 int ret; 314 331 315 - shmem_clear_channel(smbox->shmem); 332 + core->shmem->clear_channel(smbox->shmem); 316 333 317 - if (!shmem_channel_intr_enabled(smbox->shmem)) 334 + if (!core->shmem->channel_intr_enabled(smbox->shmem)) 318 335 return; 319 336 320 337 if (smbox->chan_platform_receiver) ··· 337 354 { 338 355 struct scmi_mailbox *smbox = cinfo->transport_info; 339 356 340 - return shmem_poll_done(smbox->shmem, xfer); 357 + return core->shmem->poll_done(smbox->shmem, xfer); 341 358 } 342 359 343 360 static const struct scmi_transport_ops scmi_mailbox_ops = { ··· 352 369 .poll_done = mailbox_poll_done, 353 370 }; 354 371 355 - const struct scmi_desc scmi_mailbox_desc = { 372 + static struct scmi_desc scmi_mailbox_desc = { 356 373 .ops = &scmi_mailbox_ops, 357 374 .max_rx_timeout_ms = 30, /* We may increase this if required */ 358 375 .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ 359 376 .max_msg_size = 128, 360 377 }; 378 + 379 + static const struct of_device_id scmi_of_match[] = { 380 + { .compatible = "arm,scmi" }, 381 + { /* Sentinel */ }, 382 + }; 383 + 384 + DEFINE_SCMI_TRANSPORT_DRIVER(scmi_mailbox, scmi_mailbox_driver, 385 + scmi_mailbox_desc, scmi_of_match, core); 386 + module_platform_driver(scmi_mailbox_driver); 387 + 388 + MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); 389 + MODULE_DESCRIPTION("SCMI Mailbox Transport driver"); 390 + MODULE_LICENSE("GPL");
+23 -9
drivers/firmware/arm_scmi/msg.c
··· 4 4 * 5 5 * Derived from shm.c. 6 6 * 7 - * Copyright (C) 2019-2021 ARM Ltd. 7 + * Copyright (C) 2019-2024 ARM Ltd. 8 8 * Copyright (C) 2020-2021 OpenSynergy GmbH 9 9 */ 10 10 ··· 30 30 * 31 31 * Return: transport SDU size. 32 32 */ 33 - size_t msg_command_size(struct scmi_xfer *xfer) 33 + static size_t msg_command_size(struct scmi_xfer *xfer) 34 34 { 35 35 return sizeof(struct scmi_msg_payld) + xfer->tx.len; 36 36 } ··· 42 42 * 43 43 * Return: transport SDU size. 44 44 */ 45 - size_t msg_response_size(struct scmi_xfer *xfer) 45 + static size_t msg_response_size(struct scmi_xfer *xfer) 46 46 { 47 47 return sizeof(struct scmi_msg_payld) + sizeof(__le32) + xfer->rx.len; 48 48 } ··· 53 53 * @msg: transport SDU for command 54 54 * @xfer: message which is being sent 55 55 */ 56 - void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer) 56 + static void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer) 57 57 { 58 58 msg->msg_header = cpu_to_le32(pack_scmi_header(&xfer->hdr)); 59 59 if (xfer->tx.buf) ··· 67 67 * 68 68 * Return: SCMI header 69 69 */ 70 - u32 msg_read_header(struct scmi_msg_payld *msg) 70 + static u32 msg_read_header(struct scmi_msg_payld *msg) 71 71 { 72 72 return le32_to_cpu(msg->msg_header); 73 73 } ··· 79 79 * @len: transport SDU size 80 80 * @xfer: message being responded to 81 81 */ 82 - void msg_fetch_response(struct scmi_msg_payld *msg, size_t len, 83 - struct scmi_xfer *xfer) 82 + static void msg_fetch_response(struct scmi_msg_payld *msg, 83 + size_t len, struct scmi_xfer *xfer) 84 84 { 85 85 size_t prefix_len = sizeof(*msg) + sizeof(msg->msg_payload[0]); 86 86 ··· 100 100 * @max_len: maximum SCMI payload size to fetch 101 101 * @xfer: notification message 102 102 */ 103 - void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, 104 - size_t max_len, struct scmi_xfer *xfer) 103 + static void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, 104 + size_t max_len, struct scmi_xfer *xfer) 105 105 { 106 106 xfer->rx.len = min_t(size_t, max_len, 107 107 len >= sizeof(*msg) ? len - sizeof(*msg) : 0); 108 108 109 109 /* Take a copy to the rx buffer.. */ 110 110 memcpy(xfer->rx.buf, msg->msg_payload, xfer->rx.len); 111 + } 112 + 113 + static const struct scmi_message_operations scmi_msg_ops = { 114 + .tx_prepare = msg_tx_prepare, 115 + .command_size = msg_command_size, 116 + .response_size = msg_response_size, 117 + .read_header = msg_read_header, 118 + .fetch_response = msg_fetch_response, 119 + .fetch_notification = msg_fetch_notification, 120 + }; 121 + 122 + const struct scmi_message_operations *scmi_message_operations_get(void) 123 + { 124 + return &scmi_msg_ops; 111 125 }
+57 -74
drivers/firmware/arm_scmi/optee.c drivers/firmware/arm_scmi/transports/optee.c
··· 9 9 #include <linux/kernel.h> 10 10 #include <linux/module.h> 11 11 #include <linux/mutex.h> 12 + #include <linux/platform_device.h> 12 13 #include <linux/slab.h> 13 14 #include <linux/tee_drv.h> 14 15 #include <linux/uuid.h> 15 16 #include <uapi/linux/tee.h> 16 17 17 - #include "common.h" 18 + #include "../common.h" 18 19 19 20 #define SCMI_OPTEE_MAX_MSG_SIZE 128 20 21 ··· 149 148 struct list_head channel_list; 150 149 }; 151 150 151 + static struct scmi_transport_core_operations *core; 152 + 152 153 /* There can be only 1 SCMI service in OP-TEE we connect to */ 153 154 static struct scmi_optee_agent *scmi_optee_private; 154 - 155 - /* Forward reference to scmi_optee transport initialization */ 156 - static int scmi_optee_init(void); 157 155 158 156 /* Open a session toward SCMI OP-TEE service with REE_KERNEL identity */ 159 157 static int open_session(struct scmi_optee_agent *agent, u32 *tee_session) ··· 312 312 return 0; 313 313 } 314 314 315 - static int scmi_optee_link_supplier(struct device *dev) 316 - { 317 - if (!scmi_optee_private) { 318 - if (scmi_optee_init()) 319 - dev_dbg(dev, "Optee bus not yet ready\n"); 320 - 321 - /* Wait for optee bus */ 322 - return -EPROBE_DEFER; 323 - } 324 - 325 - if (!device_link_add(dev, scmi_optee_private->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) { 326 - dev_err(dev, "Adding link to supplier optee device failed\n"); 327 - return -ECANCELED; 328 - } 329 - 330 - return 0; 331 - } 332 - 333 315 static bool scmi_optee_chan_available(struct device_node *of_node, int idx) 334 316 { 335 317 u32 channel_id; ··· 325 343 struct scmi_optee_channel *channel = cinfo->transport_info; 326 344 327 345 if (!channel->tee_shm) 328 - shmem_clear_channel(channel->req.shmem); 346 + core->shmem->clear_channel(channel->req.shmem); 329 347 } 330 348 331 349 static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *channel) ··· 350 368 static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo, 351 369 struct scmi_optee_channel *channel) 352 370 { 353 - struct device_node *np; 354 - resource_size_t size; 355 - struct resource res; 356 - int ret; 371 + channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL); 372 + if (IS_ERR(channel->req.shmem)) 373 + return PTR_ERR(channel->req.shmem); 357 374 358 - np = of_parse_phandle(cinfo->dev->of_node, "shmem", 0); 359 - if (!of_device_is_compatible(np, "arm,scmi-shmem")) { 360 - ret = -ENXIO; 361 - goto out; 362 - } 363 - 364 - ret = of_address_to_resource(np, 0, &res); 365 - if (ret) { 366 - dev_err(dev, "Failed to get SCMI Tx shared memory\n"); 367 - goto out; 368 - } 369 - 370 - size = resource_size(&res); 371 - 372 - channel->req.shmem = devm_ioremap(dev, res.start, size); 373 - if (!channel->req.shmem) { 374 - dev_err(dev, "Failed to ioremap SCMI Tx shared memory\n"); 375 - ret = -EADDRNOTAVAIL; 376 - goto out; 377 - } 378 - 379 - ret = 0; 380 - 381 - out: 382 - of_node_put(np); 383 - 384 - return ret; 375 + return 0; 385 376 } 386 377 387 378 static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo, ··· 428 473 struct scmi_chan_info *cinfo = p; 429 474 struct scmi_optee_channel *channel = cinfo->transport_info; 430 475 476 + /* 477 + * Different protocols might share the same chan info, so a previous 478 + * call might have already freed the structure. 479 + */ 480 + if (!channel) 481 + return 0; 482 + 431 483 mutex_lock(&scmi_optee_private->mu); 432 484 list_del(&channel->link); 433 485 mutex_unlock(&scmi_optee_private->mu); ··· 461 499 mutex_lock(&channel->mu); 462 500 463 501 if (channel->tee_shm) { 464 - msg_tx_prepare(channel->req.msg, xfer); 465 - ret = invoke_process_msg_channel(channel, msg_command_size(xfer)); 502 + core->msg->tx_prepare(channel->req.msg, xfer); 503 + ret = invoke_process_msg_channel(channel, 504 + core->msg->command_size(xfer)); 466 505 } else { 467 - shmem_tx_prepare(channel->req.shmem, xfer, cinfo); 506 + core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo); 468 507 ret = invoke_process_smt_channel(channel); 469 508 } 470 509 ··· 481 518 struct scmi_optee_channel *channel = cinfo->transport_info; 482 519 483 520 if (channel->tee_shm) 484 - msg_fetch_response(channel->req.msg, channel->rx_len, xfer); 521 + core->msg->fetch_response(channel->req.msg, 522 + channel->rx_len, xfer); 485 523 else 486 - shmem_fetch_response(channel->req.shmem, xfer); 524 + core->shmem->fetch_response(channel->req.shmem, xfer); 487 525 } 488 526 489 527 static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret, ··· 496 532 } 497 533 498 534 static struct scmi_transport_ops scmi_optee_ops = { 499 - .link_supplier = scmi_optee_link_supplier, 500 535 .chan_available = scmi_optee_chan_available, 501 536 .chan_setup = scmi_optee_chan_setup, 502 537 .chan_free = scmi_optee_chan_free, ··· 509 546 { 510 547 return ver->impl_id == TEE_IMPL_ID_OPTEE; 511 548 } 549 + 550 + static struct scmi_desc scmi_optee_desc = { 551 + .ops = &scmi_optee_ops, 552 + .max_rx_timeout_ms = 30, 553 + .max_msg = 20, 554 + .max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE, 555 + .sync_cmds_completed_on_ret = true, 556 + }; 557 + 558 + static const struct of_device_id scmi_of_match[] = { 559 + { .compatible = "linaro,scmi-optee" }, 560 + { /* Sentinel */ }, 561 + }; 562 + 563 + DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc, 564 + scmi_of_match, core); 512 565 513 566 static int scmi_optee_service_probe(struct device *dev) 514 567 { ··· 561 582 smp_mb(); 562 583 scmi_optee_private = agent; 563 584 585 + ret = platform_driver_register(&scmi_optee_driver); 586 + if (ret) { 587 + scmi_optee_private = NULL; 588 + goto err; 589 + } 590 + 564 591 return 0; 565 592 566 593 err: ··· 581 596 582 597 if (!scmi_optee_private) 583 598 return -EINVAL; 599 + 600 + platform_driver_unregister(&scmi_optee_driver); 584 601 585 602 if (!list_empty(&scmi_optee_private->channel_list)) 586 603 return -EBUSY; ··· 605 618 606 619 MODULE_DEVICE_TABLE(tee, scmi_optee_service_id); 607 620 608 - static struct tee_client_driver scmi_optee_driver = { 621 + static struct tee_client_driver scmi_optee_service_driver = { 609 622 .id_table = scmi_optee_service_id, 610 623 .driver = { 611 624 .name = "scmi-optee", ··· 615 628 }, 616 629 }; 617 630 618 - static int scmi_optee_init(void) 631 + static int __init scmi_transport_optee_init(void) 619 632 { 620 - return driver_register(&scmi_optee_driver.driver); 633 + return driver_register(&scmi_optee_service_driver.driver); 621 634 } 635 + module_init(scmi_transport_optee_init); 622 636 623 - static void scmi_optee_exit(void) 637 + static void __exit scmi_transport_optee_exit(void) 624 638 { 625 - if (scmi_optee_private) 626 - driver_unregister(&scmi_optee_driver.driver); 639 + driver_unregister(&scmi_optee_service_driver.driver); 627 640 } 641 + module_exit(scmi_transport_optee_exit); 628 642 629 - const struct scmi_desc scmi_optee_desc = { 630 - .transport_exit = scmi_optee_exit, 631 - .ops = &scmi_optee_ops, 632 - .max_rx_timeout_ms = 30, 633 - .max_msg = 20, 634 - .max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE, 635 - .sync_cmds_completed_on_ret = true, 636 - }; 643 + MODULE_AUTHOR("Etienne Carriere <etienne.carriere@foss.st.com>"); 644 + MODULE_DESCRIPTION("SCMI OPTEE Transport driver"); 645 + MODULE_LICENSE("GPL");
+1 -1
drivers/firmware/arm_scmi/perf.c
··· 310 310 } 311 311 if (!dom_info->mult_factor) 312 312 dev_warn(ph->dev, 313 - "Wrong sustained perf/frequency(domain %d)\n", 313 + "Wrong sustained perf/frequency(domain %d)\n", 314 314 dom_info->id); 315 315 316 316 strscpy(dom_info->info.name, attr->name,
+1
drivers/firmware/arm_scmi/pinctrl.c
··· 913 913 .ops = &pinctrl_proto_ops, 914 914 .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 915 915 }; 916 + 916 917 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(pinctrl, scmi_pinctrl)
+1 -1
drivers/firmware/arm_scmi/power.c
··· 14 14 #include "notify.h" 15 15 16 16 /* Updated only after ALL the mandatory features for that version are merged */ 17 - #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 17 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001 18 18 19 19 enum scmi_power_protocol_cmd { 20 20 POWER_DOMAIN_ATTRIBUTES = 0x3,
+1 -1
drivers/firmware/arm_scmi/reset.c
··· 14 14 #include "notify.h" 15 15 16 16 /* Updated only after ALL the mandatory features for that version are merged */ 17 - #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 17 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001 18 18 19 19 enum scmi_reset_protocol_cmd { 20 20 RESET_DOMAIN_ATTRIBUTES = 0x3,
+1 -1
drivers/firmware/arm_scmi/sensors.c
··· 15 15 #include "notify.h" 16 16 17 17 /* Updated only after ALL the mandatory features for that version are merged */ 18 - #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 18 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001 19 19 20 20 #define SCMI_MAX_NUM_SENSOR_AXIS 63 21 21 #define SCMIv2_SENSOR_PROTOCOL 0x10000
+72 -13
drivers/firmware/arm_scmi/shmem.c
··· 2 2 /* 3 3 * For transport using shared mem structure. 4 4 * 5 - * Copyright (C) 2019 ARM Ltd. 5 + * Copyright (C) 2019-2024 ARM Ltd. 6 6 */ 7 7 8 8 #include <linux/ktime.h> 9 9 #include <linux/io.h> 10 + #include <linux/of.h> 11 + #include <linux/of_address.h> 10 12 #include <linux/processor.h> 11 13 #include <linux/types.h> 12 14 ··· 34 32 u8 msg_payload[]; 35 33 }; 36 34 37 - void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, 38 - struct scmi_xfer *xfer, struct scmi_chan_info *cinfo) 35 + static void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, 36 + struct scmi_xfer *xfer, 37 + struct scmi_chan_info *cinfo) 39 38 { 40 39 ktime_t stop; 41 40 ··· 76 73 memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); 77 74 } 78 75 79 - u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) 76 + static u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) 80 77 { 81 78 return ioread32(&shmem->msg_header); 82 79 } 83 80 84 - void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, 85 - struct scmi_xfer *xfer) 81 + static void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, 82 + struct scmi_xfer *xfer) 86 83 { 87 84 size_t len = ioread32(&shmem->length); 88 85 ··· 94 91 memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); 95 92 } 96 93 97 - void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, 98 - size_t max_len, struct scmi_xfer *xfer) 94 + static void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, 95 + size_t max_len, struct scmi_xfer *xfer) 99 96 { 100 97 size_t len = ioread32(&shmem->length); 101 98 ··· 106 103 memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); 107 104 } 108 105 109 - void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) 106 + static void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) 110 107 { 111 108 iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status); 112 109 } 113 110 114 - bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, 115 - struct scmi_xfer *xfer) 111 + static bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, 112 + struct scmi_xfer *xfer) 116 113 { 117 114 u16 xfer_id; 118 115 ··· 126 123 SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); 127 124 } 128 125 129 - bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) 126 + static bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) 130 127 { 131 128 return (ioread32(&shmem->channel_status) & 132 129 SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); 133 130 } 134 131 135 - bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) 132 + static bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) 136 133 { 137 134 return ioread32(&shmem->flags) & SCMI_SHMEM_FLAG_INTR_ENABLED; 135 + } 136 + 137 + static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo, 138 + struct device *dev, bool tx, 139 + struct resource *res) 140 + { 141 + struct device_node *shmem __free(device_node); 142 + const char *desc = tx ? "Tx" : "Rx"; 143 + int ret, idx = tx ? 0 : 1; 144 + struct device *cdev = cinfo->dev; 145 + struct resource lres = {}; 146 + resource_size_t size; 147 + void __iomem *addr; 148 + 149 + shmem = of_parse_phandle(cdev->of_node, "shmem", idx); 150 + if (!shmem) 151 + return IOMEM_ERR_PTR(-ENODEV); 152 + 153 + if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) 154 + return IOMEM_ERR_PTR(-ENXIO); 155 + 156 + /* Use a local on-stack as a working area when not provided */ 157 + if (!res) 158 + res = &lres; 159 + 160 + ret = of_address_to_resource(shmem, 0, res); 161 + if (ret) { 162 + dev_err(cdev, "failed to get SCMI %s shared memory\n", desc); 163 + return IOMEM_ERR_PTR(ret); 164 + } 165 + 166 + size = resource_size(res); 167 + addr = devm_ioremap(dev, res->start, size); 168 + if (!addr) { 169 + dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc); 170 + return IOMEM_ERR_PTR(-EADDRNOTAVAIL); 171 + } 172 + 173 + return addr; 174 + } 175 + 176 + static const struct scmi_shared_mem_operations scmi_shmem_ops = { 177 + .tx_prepare = shmem_tx_prepare, 178 + .read_header = shmem_read_header, 179 + .fetch_response = shmem_fetch_response, 180 + .fetch_notification = shmem_fetch_notification, 181 + .clear_channel = shmem_clear_channel, 182 + .poll_done = shmem_poll_done, 183 + .channel_free = shmem_channel_free, 184 + .channel_intr_enabled = shmem_channel_intr_enabled, 185 + .setup_iomap = shmem_setup_iomap, 186 + }; 187 + 188 + const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void) 189 + { 190 + return &scmi_shmem_ops; 138 191 }
+32 -30
drivers/firmware/arm_scmi/smc.c drivers/firmware/arm_scmi/transports/smc.c
··· 16 16 #include <linux/of_address.h> 17 17 #include <linux/of_irq.h> 18 18 #include <linux/limits.h> 19 + #include <linux/platform_device.h> 19 20 #include <linux/processor.h> 20 21 #include <linux/slab.h> 21 22 22 - #include "common.h" 23 + #include "../common.h" 23 24 24 25 /* 25 26 * The shmem address is split into 4K page and offset. ··· 70 69 unsigned long cap_id; 71 70 }; 72 71 72 + static struct scmi_transport_core_operations *core; 73 + 73 74 static irqreturn_t smc_msg_done_isr(int irq, void *data) 74 75 { 75 76 struct scmi_smc *scmi_info = data; 76 77 77 - scmi_rx_callback(scmi_info->cinfo, 78 - shmem_read_header(scmi_info->shmem), NULL); 78 + core->rx_callback(scmi_info->cinfo, 79 + core->shmem->read_header(scmi_info->shmem), NULL); 79 80 80 81 return IRQ_HANDLED; 81 82 } 82 83 83 84 static bool smc_chan_available(struct device_node *of_node, int idx) 84 85 { 85 - struct device_node *np = of_parse_phandle(of_node, "shmem", 0); 86 + struct device_node *np __free(device_node) = 87 + of_parse_phandle(of_node, "shmem", 0); 86 88 if (!np) 87 89 return false; 88 90 89 - of_node_put(np); 90 91 return true; 91 92 } 92 93 ··· 133 130 struct device *cdev = cinfo->dev; 134 131 unsigned long cap_id = ULONG_MAX; 135 132 struct scmi_smc *scmi_info; 136 - resource_size_t size; 137 - struct resource res; 138 - struct device_node *np; 133 + struct resource res = {}; 139 134 u32 func_id; 140 135 int ret; 141 136 ··· 144 143 if (!scmi_info) 145 144 return -ENOMEM; 146 145 147 - np = of_parse_phandle(cdev->of_node, "shmem", 0); 148 - if (!of_device_is_compatible(np, "arm,scmi-shmem")) { 149 - of_node_put(np); 150 - return -ENXIO; 151 - } 152 - 153 - ret = of_address_to_resource(np, 0, &res); 154 - of_node_put(np); 155 - if (ret) { 156 - dev_err(cdev, "failed to get SCMI Tx shared memory\n"); 157 - return ret; 158 - } 159 - 160 - size = resource_size(&res); 161 - scmi_info->shmem = devm_ioremap(dev, res.start, size); 162 - if (!scmi_info->shmem) { 163 - dev_err(dev, "failed to ioremap SCMI Tx shared memory\n"); 164 - return -EADDRNOTAVAIL; 165 - } 146 + scmi_info->shmem = core->shmem->setup_iomap(cinfo, dev, tx, &res); 147 + if (IS_ERR(scmi_info->shmem)) 148 + return PTR_ERR(scmi_info->shmem); 166 149 167 150 ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id); 168 151 if (ret < 0) 169 152 return ret; 170 153 171 154 if (of_device_is_compatible(dev->of_node, "qcom,scmi-smc")) { 155 + resource_size_t size = resource_size(&res); 172 156 void __iomem *ptr = (void __iomem *)scmi_info->shmem + size - 8; 173 157 /* The capability-id is kept in last 8 bytes of shmem. 174 158 * +-------+ <-- 0 ··· 229 243 */ 230 244 smc_channel_lock_acquire(scmi_info, xfer); 231 245 232 - shmem_tx_prepare(scmi_info->shmem, xfer, cinfo); 246 + core->shmem->tx_prepare(scmi_info->shmem, xfer, cinfo); 233 247 234 248 if (scmi_info->cap_id != ULONG_MAX) 235 249 arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0, ··· 253 267 { 254 268 struct scmi_smc *scmi_info = cinfo->transport_info; 255 269 256 - shmem_fetch_response(scmi_info->shmem, xfer); 270 + core->shmem->fetch_response(scmi_info->shmem, xfer); 257 271 } 258 272 259 273 static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret, ··· 273 287 .fetch_response = smc_fetch_response, 274 288 }; 275 289 276 - const struct scmi_desc scmi_smc_desc = { 290 + static struct scmi_desc scmi_smc_desc = { 277 291 .ops = &scmi_smc_ops, 278 292 .max_rx_timeout_ms = 30, 279 293 .max_msg = 20, ··· 289 303 .sync_cmds_completed_on_ret = true, 290 304 .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE), 291 305 }; 306 + 307 + static const struct of_device_id scmi_of_match[] = { 308 + { .compatible = "arm,scmi-smc" }, 309 + { .compatible = "arm,scmi-smc-param" }, 310 + { .compatible = "qcom,scmi-smc" }, 311 + { /* Sentinel */ }, 312 + }; 313 + 314 + DEFINE_SCMI_TRANSPORT_DRIVER(scmi_smc, scmi_smc_driver, scmi_smc_desc, 315 + scmi_of_match, core); 316 + module_platform_driver(scmi_smc_driver); 317 + 318 + MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 319 + MODULE_AUTHOR("Nikunj Kela <quic_nkela@quicinc.com>"); 320 + MODULE_DESCRIPTION("SCMI SMC Transport driver"); 321 + MODULE_LICENSE("GPL");
+1 -1
drivers/firmware/arm_scmi/system.c
··· 14 14 #include "notify.h" 15 15 16 16 /* Updated only after ALL the mandatory features for that version are merged */ 17 - #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 17 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 18 18 19 19 #define SCMI_SYSTEM_NUM_SOURCES 1 20 20
+123
drivers/firmware/arm_scmi/transports/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + menu "SCMI Transport Drivers" 3 + 4 + config ARM_SCMI_HAVE_TRANSPORT 5 + bool 6 + help 7 + This declares whether at least one SCMI transport has been configured. 8 + Used to trigger a build bug when trying to build SCMI without any 9 + configured transport. 10 + 11 + config ARM_SCMI_HAVE_SHMEM 12 + bool 13 + help 14 + This declares whether a shared memory based transport for SCMI is 15 + available. 16 + 17 + config ARM_SCMI_HAVE_MSG 18 + bool 19 + help 20 + This declares whether a message passing based transport for SCMI is 21 + available. 22 + 23 + config ARM_SCMI_TRANSPORT_MAILBOX 24 + tristate "SCMI transport based on Mailbox" 25 + depends on MAILBOX 26 + select ARM_SCMI_HAVE_TRANSPORT 27 + select ARM_SCMI_HAVE_SHMEM 28 + default y 29 + help 30 + Enable mailbox based transport for SCMI. 31 + 32 + If you want the ARM SCMI PROTOCOL stack to include support for a 33 + transport based on mailboxes, answer Y. 34 + This driver can also be built as a module. If so, the module 35 + will be called scmi_transport_mailbox. 36 + 37 + config ARM_SCMI_TRANSPORT_SMC 38 + tristate "SCMI transport based on SMC" 39 + depends on HAVE_ARM_SMCCC_DISCOVERY 40 + select ARM_SCMI_HAVE_TRANSPORT 41 + select ARM_SCMI_HAVE_SHMEM 42 + default y 43 + help 44 + Enable SMC based transport for SCMI. 45 + 46 + If you want the ARM SCMI PROTOCOL stack to include support for a 47 + transport based on SMC, answer Y. 48 + This driver can also be built as a module. If so, the module 49 + will be called scmi_transport_smc. 50 + 51 + config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE 52 + bool "Enable atomic mode support for SCMI SMC transport" 53 + depends on ARM_SCMI_TRANSPORT_SMC 54 + help 55 + Enable support of atomic operation for SCMI SMC based transport. 56 + 57 + If you want the SCMI SMC based transport to operate in atomic 58 + mode, avoiding any kind of sleeping behaviour for selected 59 + transactions on the TX path, answer Y. 60 + Enabling atomic mode operations allows any SCMI driver using this 61 + transport to optionally ask for atomic SCMI transactions and operate 62 + in atomic context too, at the price of using a number of busy-waiting 63 + primitives all over instead. If unsure say N. 64 + 65 + config ARM_SCMI_TRANSPORT_OPTEE 66 + tristate "SCMI transport based on OP-TEE service" 67 + depends on OPTEE 68 + select ARM_SCMI_HAVE_TRANSPORT 69 + select ARM_SCMI_HAVE_SHMEM 70 + select ARM_SCMI_HAVE_MSG 71 + default y 72 + help 73 + This enables the OP-TEE service based transport for SCMI. 74 + 75 + If you want the ARM SCMI PROTOCOL stack to include support for a 76 + transport based on OP-TEE SCMI service, answer Y. 77 + This driver can also be built as a module. If so, the module 78 + will be called scmi_transport_optee. 79 + 80 + config ARM_SCMI_TRANSPORT_VIRTIO 81 + tristate "SCMI transport based on VirtIO" 82 + depends on VIRTIO 83 + select ARM_SCMI_HAVE_TRANSPORT 84 + select ARM_SCMI_HAVE_MSG 85 + help 86 + This enables the virtio based transport for SCMI. 87 + 88 + If you want the ARM SCMI PROTOCOL stack to include support for a 89 + transport based on VirtIO, answer Y. 90 + This driver can also be built as a module. If so, the module 91 + will be called scmi_transport_virtio. 92 + 93 + config ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE 94 + bool "SCMI VirtIO transport Version 1 compliance" 95 + depends on ARM_SCMI_TRANSPORT_VIRTIO 96 + default y 97 + help 98 + This enforces strict compliance with VirtIO Version 1 specification. 99 + 100 + If you want the ARM SCMI VirtIO transport layer to refuse to work 101 + with Legacy VirtIO backends and instead support only VirtIO Version 1 102 + devices (or above), answer Y. 103 + 104 + If you want instead to support also old Legacy VirtIO backends (like 105 + the ones implemented by kvmtool) and let the core Kernel VirtIO layer 106 + take care of the needed conversions, say N. 107 + 108 + config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE 109 + bool "Enable atomic mode for SCMI VirtIO transport" 110 + depends on ARM_SCMI_TRANSPORT_VIRTIO 111 + help 112 + Enable support of atomic operation for SCMI VirtIO based transport. 113 + 114 + If you want the SCMI VirtIO based transport to operate in atomic 115 + mode, avoiding any kind of sleeping behaviour for selected 116 + transactions on the TX path, answer Y. 117 + 118 + Enabling atomic mode operations allows any SCMI driver using this 119 + transport to optionally ask for atomic SCMI transactions and operate 120 + in atomic context too, at the price of using a number of busy-waiting 121 + primitives all over instead. If unsure say N. 122 + 123 + endmenu
+16
drivers/firmware/arm_scmi/transports/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + scmi_transport_mailbox-objs := mailbox.o 3 + obj-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += scmi_transport_mailbox.o 4 + scmi_transport_smc-objs := smc.o 5 + obj-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += scmi_transport_smc.o 6 + scmi_transport_optee-objs := optee.o 7 + obj-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += scmi_transport_optee.o 8 + scmi_transport_virtio-objs := virtio.o 9 + obj-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += scmi_transport_virtio.o 10 + 11 + ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) 12 + # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame 13 + # pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling 14 + # hooks are inserted via the -pg switch. 15 + CFLAGS_REMOVE_smc.o += $(CC_FLAGS_FTRACE) 16 + endif
+25
drivers/firmware/arm_scmi/vendors/imx/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + menu "ARM SCMI NXP i.MX Vendor Protocols" 3 + 4 + config IMX_SCMI_BBM_EXT 5 + tristate "i.MX SCMI BBM EXTENSION" 6 + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) 7 + default y if ARCH_MXC 8 + help 9 + This enables i.MX System BBM control logic which supports RTC 10 + and BUTTON. 11 + 12 + To compile this driver as a module, choose M here: the 13 + module will be called imx-sm-bbm. 14 + 15 + config IMX_SCMI_MISC_EXT 16 + tristate "i.MX SCMI MISC EXTENSION" 17 + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) 18 + default y if ARCH_MXC 19 + help 20 + This enables i.MX System MISC control logic such as gpio expander 21 + wakeup 22 + 23 + To compile this driver as a module, choose M here: the 24 + module will be called imx-sm-misc. 25 + endmenu
+3
drivers/firmware/arm_scmi/vendors/imx/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + obj-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o 3 + obj-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o
+383
drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * System Control and Management Interface (SCMI) NXP BBM Protocol 4 + * 5 + * Copyright 2024 NXP 6 + */ 7 + 8 + #define pr_fmt(fmt) "SCMI Notifications BBM - " fmt 9 + 10 + #include <linux/bits.h> 11 + #include <linux/io.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/scmi_protocol.h> 16 + #include <linux/scmi_imx_protocol.h> 17 + 18 + #include "../../protocols.h" 19 + #include "../../notify.h" 20 + 21 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000 22 + 23 + enum scmi_imx_bbm_protocol_cmd { 24 + IMX_BBM_GPR_SET = 0x3, 25 + IMX_BBM_GPR_GET = 0x4, 26 + IMX_BBM_RTC_ATTRIBUTES = 0x5, 27 + IMX_BBM_RTC_TIME_SET = 0x6, 28 + IMX_BBM_RTC_TIME_GET = 0x7, 29 + IMX_BBM_RTC_ALARM_SET = 0x8, 30 + IMX_BBM_BUTTON_GET = 0x9, 31 + IMX_BBM_RTC_NOTIFY = 0xA, 32 + IMX_BBM_BUTTON_NOTIFY = 0xB, 33 + }; 34 + 35 + #define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16)) 36 + #define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0)) 37 + 38 + #define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2) 39 + #define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1) 40 + #define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0) 41 + 42 + #define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0) 43 + 44 + #define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \ 45 + (SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \ 46 + SCMI_IMX_BBM_NOTIFY_RTC_ALARM) 47 + 48 + #define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24) 49 + 50 + struct scmi_imx_bbm_info { 51 + u32 version; 52 + int nr_rtc; 53 + int nr_gpr; 54 + }; 55 + 56 + struct scmi_msg_imx_bbm_protocol_attributes { 57 + __le32 attributes; 58 + }; 59 + 60 + struct scmi_imx_bbm_set_time { 61 + __le32 id; 62 + __le32 flags; 63 + __le32 value_low; 64 + __le32 value_high; 65 + }; 66 + 67 + struct scmi_imx_bbm_get_time { 68 + __le32 id; 69 + __le32 flags; 70 + }; 71 + 72 + struct scmi_imx_bbm_alarm_time { 73 + __le32 id; 74 + __le32 flags; 75 + __le32 value_low; 76 + __le32 value_high; 77 + }; 78 + 79 + struct scmi_msg_imx_bbm_rtc_notify { 80 + __le32 rtc_id; 81 + __le32 flags; 82 + }; 83 + 84 + struct scmi_msg_imx_bbm_button_notify { 85 + __le32 flags; 86 + }; 87 + 88 + struct scmi_imx_bbm_notify_payld { 89 + __le32 flags; 90 + }; 91 + 92 + static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph, 93 + struct scmi_imx_bbm_info *pi) 94 + { 95 + int ret; 96 + struct scmi_xfer *t; 97 + struct scmi_msg_imx_bbm_protocol_attributes *attr; 98 + 99 + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t); 100 + if (ret) 101 + return ret; 102 + 103 + attr = t->rx.buf; 104 + 105 + ret = ph->xops->do_xfer(ph, t); 106 + if (!ret) { 107 + pi->nr_rtc = GET_RTCS_NR(attr->attributes); 108 + pi->nr_gpr = GET_GPRS_NR(attr->attributes); 109 + } 110 + 111 + ph->xops->xfer_put(ph, t); 112 + 113 + return ret; 114 + } 115 + 116 + static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph, 117 + u32 src_id, int message_id, bool enable) 118 + { 119 + int ret; 120 + struct scmi_xfer *t; 121 + 122 + if (message_id == IMX_BBM_RTC_NOTIFY) { 123 + struct scmi_msg_imx_bbm_rtc_notify *rtc_notify; 124 + 125 + ret = ph->xops->xfer_get_init(ph, message_id, 126 + sizeof(*rtc_notify), 0, &t); 127 + if (ret) 128 + return ret; 129 + 130 + rtc_notify = t->tx.buf; 131 + rtc_notify->rtc_id = cpu_to_le32(0); 132 + rtc_notify->flags = 133 + cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0); 134 + } else if (message_id == IMX_BBM_BUTTON_NOTIFY) { 135 + struct scmi_msg_imx_bbm_button_notify *button_notify; 136 + 137 + ret = ph->xops->xfer_get_init(ph, message_id, 138 + sizeof(*button_notify), 0, &t); 139 + if (ret) 140 + return ret; 141 + 142 + button_notify = t->tx.buf; 143 + button_notify->flags = cpu_to_le32(enable ? 1 : 0); 144 + } else { 145 + return -EINVAL; 146 + } 147 + 148 + ret = ph->xops->do_xfer(ph, t); 149 + 150 + ph->xops->xfer_put(ph, t); 151 + return ret; 152 + } 153 + 154 + static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = { 155 + IMX_BBM_RTC_NOTIFY, 156 + IMX_BBM_BUTTON_NOTIFY 157 + }; 158 + 159 + static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph, 160 + u8 evt_id, u32 src_id, bool enable) 161 + { 162 + int ret, cmd_id; 163 + 164 + if (evt_id >= ARRAY_SIZE(evt_2_cmd)) 165 + return -EINVAL; 166 + 167 + cmd_id = evt_2_cmd[evt_id]; 168 + ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable); 169 + if (ret) 170 + pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", 171 + evt_id, src_id, ret); 172 + 173 + return ret; 174 + } 175 + 176 + static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph, 177 + u8 evt_id, ktime_t timestamp, 178 + const void *payld, size_t payld_sz, 179 + void *report, u32 *src_id) 180 + { 181 + const struct scmi_imx_bbm_notify_payld *p = payld; 182 + struct scmi_imx_bbm_notif_report *r = report; 183 + 184 + if (sizeof(*p) != payld_sz) 185 + return NULL; 186 + 187 + if (evt_id == SCMI_EVENT_IMX_BBM_RTC) { 188 + r->is_rtc = true; 189 + r->is_button = false; 190 + r->timestamp = timestamp; 191 + r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK); 192 + r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG); 193 + dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt); 194 + *src_id = r->rtc_evt; 195 + } else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) { 196 + r->is_rtc = false; 197 + r->is_button = true; 198 + r->timestamp = timestamp; 199 + dev_dbg(ph->dev, "BBM Button\n"); 200 + *src_id = 0; 201 + } else { 202 + WARN_ON_ONCE(1); 203 + return NULL; 204 + } 205 + 206 + return r; 207 + } 208 + 209 + static const struct scmi_event scmi_imx_bbm_events[] = { 210 + { 211 + .id = SCMI_EVENT_IMX_BBM_RTC, 212 + .max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld), 213 + .max_report_sz = sizeof(struct scmi_imx_bbm_notif_report), 214 + }, 215 + { 216 + .id = SCMI_EVENT_IMX_BBM_BUTTON, 217 + .max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld), 218 + .max_report_sz = sizeof(struct scmi_imx_bbm_notif_report), 219 + }, 220 + }; 221 + 222 + static const struct scmi_event_ops scmi_imx_bbm_event_ops = { 223 + .set_notify_enabled = scmi_imx_bbm_set_notify_enabled, 224 + .fill_custom_report = scmi_imx_bbm_fill_custom_report, 225 + }; 226 + 227 + static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = { 228 + .queue_sz = SCMI_PROTO_QUEUE_SZ, 229 + .ops = &scmi_imx_bbm_event_ops, 230 + .evts = scmi_imx_bbm_events, 231 + .num_events = ARRAY_SIZE(scmi_imx_bbm_events), 232 + .num_sources = 1, 233 + }; 234 + 235 + static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph, 236 + u32 rtc_id, u64 sec) 237 + { 238 + struct scmi_imx_bbm_info *pi = ph->get_priv(ph); 239 + struct scmi_imx_bbm_set_time *cfg; 240 + struct scmi_xfer *t; 241 + int ret; 242 + 243 + if (rtc_id >= pi->nr_rtc) 244 + return -EINVAL; 245 + 246 + ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t); 247 + if (ret) 248 + return ret; 249 + 250 + cfg = t->tx.buf; 251 + cfg->id = cpu_to_le32(rtc_id); 252 + cfg->flags = 0; 253 + cfg->value_low = cpu_to_le32(lower_32_bits(sec)); 254 + cfg->value_high = cpu_to_le32(upper_32_bits(sec)); 255 + 256 + ret = ph->xops->do_xfer(ph, t); 257 + 258 + ph->xops->xfer_put(ph, t); 259 + 260 + return ret; 261 + } 262 + 263 + static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph, 264 + u32 rtc_id, u64 *value) 265 + { 266 + struct scmi_imx_bbm_info *pi = ph->get_priv(ph); 267 + struct scmi_imx_bbm_get_time *cfg; 268 + struct scmi_xfer *t; 269 + int ret; 270 + 271 + if (rtc_id >= pi->nr_rtc) 272 + return -EINVAL; 273 + 274 + ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg), 275 + sizeof(u64), &t); 276 + if (ret) 277 + return ret; 278 + 279 + cfg = t->tx.buf; 280 + cfg->id = cpu_to_le32(rtc_id); 281 + cfg->flags = 0; 282 + 283 + ret = ph->xops->do_xfer(ph, t); 284 + if (!ret) 285 + *value = get_unaligned_le64(t->rx.buf); 286 + 287 + ph->xops->xfer_put(ph, t); 288 + 289 + return ret; 290 + } 291 + 292 + static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph, 293 + u32 rtc_id, bool enable, u64 sec) 294 + { 295 + struct scmi_imx_bbm_info *pi = ph->get_priv(ph); 296 + struct scmi_imx_bbm_alarm_time *cfg; 297 + struct scmi_xfer *t; 298 + int ret; 299 + 300 + if (rtc_id >= pi->nr_rtc) 301 + return -EINVAL; 302 + 303 + ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t); 304 + if (ret) 305 + return ret; 306 + 307 + cfg = t->tx.buf; 308 + cfg->id = cpu_to_le32(rtc_id); 309 + cfg->flags = enable ? 310 + cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0; 311 + cfg->value_low = cpu_to_le32(lower_32_bits(sec)); 312 + cfg->value_high = cpu_to_le32(upper_32_bits(sec)); 313 + 314 + ret = ph->xops->do_xfer(ph, t); 315 + 316 + ph->xops->xfer_put(ph, t); 317 + 318 + return ret; 319 + } 320 + 321 + static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state) 322 + { 323 + struct scmi_xfer *t; 324 + int ret; 325 + 326 + ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t); 327 + if (ret) 328 + return ret; 329 + 330 + ret = ph->xops->do_xfer(ph, t); 331 + if (!ret) 332 + *state = get_unaligned_le32(t->rx.buf); 333 + 334 + ph->xops->xfer_put(ph, t); 335 + 336 + return ret; 337 + } 338 + 339 + static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = { 340 + .rtc_time_get = scmi_imx_bbm_rtc_time_get, 341 + .rtc_time_set = scmi_imx_bbm_rtc_time_set, 342 + .rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set, 343 + .button_get = scmi_imx_bbm_button_get, 344 + }; 345 + 346 + static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph) 347 + { 348 + u32 version; 349 + int ret; 350 + struct scmi_imx_bbm_info *binfo; 351 + 352 + ret = ph->xops->version_get(ph, &version); 353 + if (ret) 354 + return ret; 355 + 356 + dev_info(ph->dev, "NXP SM BBM Version %d.%d\n", 357 + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 358 + 359 + binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL); 360 + if (!binfo) 361 + return -ENOMEM; 362 + 363 + ret = scmi_imx_bbm_attributes_get(ph, binfo); 364 + if (ret) 365 + return ret; 366 + 367 + return ph->set_priv(ph, binfo, version); 368 + } 369 + 370 + static const struct scmi_protocol scmi_imx_bbm = { 371 + .id = SCMI_PROTOCOL_IMX_BBM, 372 + .owner = THIS_MODULE, 373 + .instance_init = &scmi_imx_bbm_protocol_init, 374 + .ops = &scmi_imx_bbm_proto_ops, 375 + .events = &scmi_imx_bbm_protocol_events, 376 + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 377 + .vendor_id = "NXP", 378 + .sub_vendor_id = "IMX", 379 + }; 380 + module_scmi_protocol(scmi_imx_bbm); 381 + 382 + MODULE_DESCRIPTION("i.MX SCMI BBM driver"); 383 + MODULE_LICENSE("GPL");
+318
drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * System control and Management Interface (SCMI) NXP MISC Protocol 4 + * 5 + * Copyright 2024 NXP 6 + */ 7 + 8 + #define pr_fmt(fmt) "SCMI Notifications MISC - " fmt 9 + 10 + #include <linux/bits.h> 11 + #include <linux/io.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/scmi_protocol.h> 16 + #include <linux/scmi_imx_protocol.h> 17 + 18 + #include "../../protocols.h" 19 + #include "../../notify.h" 20 + 21 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000 22 + 23 + #define MAX_MISC_CTRL_SOURCES GENMASK(15, 0) 24 + 25 + enum scmi_imx_misc_protocol_cmd { 26 + SCMI_IMX_MISC_CTRL_SET = 0x3, 27 + SCMI_IMX_MISC_CTRL_GET = 0x4, 28 + SCMI_IMX_MISC_CTRL_NOTIFY = 0x8, 29 + }; 30 + 31 + struct scmi_imx_misc_info { 32 + u32 version; 33 + u32 nr_dev_ctrl; 34 + u32 nr_brd_ctrl; 35 + u32 nr_reason; 36 + }; 37 + 38 + struct scmi_msg_imx_misc_protocol_attributes { 39 + __le32 attributes; 40 + }; 41 + 42 + #define GET_BRD_CTRLS_NR(x) le32_get_bits((x), GENMASK(31, 24)) 43 + #define GET_REASONS_NR(x) le32_get_bits((x), GENMASK(23, 16)) 44 + #define GET_DEV_CTRLS_NR(x) le32_get_bits((x), GENMASK(15, 0)) 45 + #define BRD_CTRL_START_ID BIT(15) 46 + 47 + struct scmi_imx_misc_ctrl_set_in { 48 + __le32 id; 49 + __le32 num; 50 + __le32 value[]; 51 + }; 52 + 53 + struct scmi_imx_misc_ctrl_notify_in { 54 + __le32 ctrl_id; 55 + __le32 flags; 56 + }; 57 + 58 + struct scmi_imx_misc_ctrl_notify_payld { 59 + __le32 ctrl_id; 60 + __le32 flags; 61 + }; 62 + 63 + struct scmi_imx_misc_ctrl_get_out { 64 + __le32 num; 65 + __le32 val[]; 66 + }; 67 + 68 + static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph, 69 + struct scmi_imx_misc_info *mi) 70 + { 71 + int ret; 72 + struct scmi_xfer *t; 73 + struct scmi_msg_imx_misc_protocol_attributes *attr; 74 + 75 + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, 76 + sizeof(*attr), &t); 77 + if (ret) 78 + return ret; 79 + 80 + attr = t->rx.buf; 81 + 82 + ret = ph->xops->do_xfer(ph, t); 83 + if (!ret) { 84 + mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes); 85 + mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes); 86 + mi->nr_reason = GET_REASONS_NR(attr->attributes); 87 + dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n", 88 + mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason); 89 + } 90 + 91 + ph->xops->xfer_put(ph, t); 92 + 93 + return ret; 94 + } 95 + 96 + static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph, 97 + u32 ctrl_id) 98 + { 99 + struct scmi_imx_misc_info *mi = ph->get_priv(ph); 100 + 101 + /* 102 + * [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related 103 + * [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related 104 + */ 105 + if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl) 106 + return -EINVAL; 107 + if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl) 108 + return -EINVAL; 109 + 110 + return 0; 111 + } 112 + 113 + static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph, 114 + u32 ctrl_id, u32 evt_id, u32 flags) 115 + { 116 + struct scmi_imx_misc_ctrl_notify_in *in; 117 + struct scmi_xfer *t; 118 + int ret; 119 + 120 + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); 121 + if (ret) 122 + return ret; 123 + 124 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY, 125 + sizeof(*in), 0, &t); 126 + if (ret) 127 + return ret; 128 + 129 + in = t->tx.buf; 130 + in->ctrl_id = cpu_to_le32(ctrl_id); 131 + in->flags = cpu_to_le32(flags); 132 + 133 + ret = ph->xops->do_xfer(ph, t); 134 + 135 + ph->xops->xfer_put(ph, t); 136 + 137 + return ret; 138 + } 139 + 140 + static int 141 + scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph, 142 + u8 evt_id, u32 src_id, bool enable) 143 + { 144 + int ret; 145 + 146 + /* misc_ctrl_req_notify is for enablement */ 147 + if (enable) 148 + return 0; 149 + 150 + ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0); 151 + if (ret) 152 + dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n", 153 + evt_id, src_id, ret); 154 + 155 + return ret; 156 + } 157 + 158 + static void * 159 + scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph, 160 + u8 evt_id, ktime_t timestamp, 161 + const void *payld, size_t payld_sz, 162 + void *report, u32 *src_id) 163 + { 164 + const struct scmi_imx_misc_ctrl_notify_payld *p = payld; 165 + struct scmi_imx_misc_ctrl_notify_report *r = report; 166 + 167 + if (sizeof(*p) != payld_sz) 168 + return NULL; 169 + 170 + r->timestamp = timestamp; 171 + r->ctrl_id = le32_to_cpu(p->ctrl_id); 172 + r->flags = le32_to_cpu(p->flags); 173 + if (src_id) 174 + *src_id = r->ctrl_id; 175 + dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__, 176 + r->ctrl_id, r->flags); 177 + 178 + return r; 179 + } 180 + 181 + static const struct scmi_event_ops scmi_imx_misc_event_ops = { 182 + .set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled, 183 + .fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report, 184 + }; 185 + 186 + static const struct scmi_event scmi_imx_misc_events[] = { 187 + { 188 + .id = SCMI_EVENT_IMX_MISC_CONTROL, 189 + .max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld), 190 + .max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report), 191 + }, 192 + }; 193 + 194 + static struct scmi_protocol_events scmi_imx_misc_protocol_events = { 195 + .queue_sz = SCMI_PROTO_QUEUE_SZ, 196 + .ops = &scmi_imx_misc_event_ops, 197 + .evts = scmi_imx_misc_events, 198 + .num_events = ARRAY_SIZE(scmi_imx_misc_events), 199 + .num_sources = MAX_MISC_CTRL_SOURCES, 200 + }; 201 + 202 + static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph, 203 + u32 ctrl_id, u32 *num, u32 *val) 204 + { 205 + struct scmi_imx_misc_ctrl_get_out *out; 206 + struct scmi_xfer *t; 207 + int ret, i; 208 + int max_msg_size = ph->hops->get_max_msg_size(ph); 209 + int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32); 210 + 211 + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); 212 + if (ret) 213 + return ret; 214 + 215 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32), 216 + 0, &t); 217 + if (ret) 218 + return ret; 219 + 220 + put_unaligned_le32(ctrl_id, t->tx.buf); 221 + ret = ph->xops->do_xfer(ph, t); 222 + if (!ret) { 223 + out = t->rx.buf; 224 + *num = le32_to_cpu(out->num); 225 + 226 + if (*num >= max_num || 227 + *num * sizeof(__le32) > t->rx.len - sizeof(__le32)) { 228 + ph->xops->xfer_put(ph, t); 229 + return -EINVAL; 230 + } 231 + 232 + for (i = 0; i < *num; i++) 233 + val[i] = le32_to_cpu(out->val[i]); 234 + } 235 + 236 + ph->xops->xfer_put(ph, t); 237 + 238 + return ret; 239 + } 240 + 241 + static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph, 242 + u32 ctrl_id, u32 num, u32 *val) 243 + { 244 + struct scmi_imx_misc_ctrl_set_in *in; 245 + struct scmi_xfer *t; 246 + int ret, i; 247 + int max_msg_size = ph->hops->get_max_msg_size(ph); 248 + int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32); 249 + 250 + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); 251 + if (ret) 252 + return ret; 253 + 254 + if (num > max_num) 255 + return -EINVAL; 256 + 257 + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, sizeof(*in), 258 + 0, &t); 259 + if (ret) 260 + return ret; 261 + 262 + in = t->tx.buf; 263 + in->id = cpu_to_le32(ctrl_id); 264 + in->num = cpu_to_le32(num); 265 + for (i = 0; i < num; i++) 266 + in->value[i] = cpu_to_le32(val[i]); 267 + 268 + ret = ph->xops->do_xfer(ph, t); 269 + 270 + ph->xops->xfer_put(ph, t); 271 + 272 + return ret; 273 + } 274 + 275 + static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = { 276 + .misc_ctrl_set = scmi_imx_misc_ctrl_set, 277 + .misc_ctrl_get = scmi_imx_misc_ctrl_get, 278 + .misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify, 279 + }; 280 + 281 + static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph) 282 + { 283 + struct scmi_imx_misc_info *minfo; 284 + u32 version; 285 + int ret; 286 + 287 + ret = ph->xops->version_get(ph, &version); 288 + if (ret) 289 + return ret; 290 + 291 + dev_info(ph->dev, "NXP SM MISC Version %d.%d\n", 292 + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 293 + 294 + minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL); 295 + if (!minfo) 296 + return -ENOMEM; 297 + 298 + ret = scmi_imx_misc_attributes_get(ph, minfo); 299 + if (ret) 300 + return ret; 301 + 302 + return ph->set_priv(ph, minfo, version); 303 + } 304 + 305 + static const struct scmi_protocol scmi_imx_misc = { 306 + .id = SCMI_PROTOCOL_IMX_MISC, 307 + .owner = THIS_MODULE, 308 + .instance_init = &scmi_imx_misc_protocol_init, 309 + .ops = &scmi_imx_misc_proto_ops, 310 + .events = &scmi_imx_misc_protocol_events, 311 + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 312 + .vendor_id = "NXP", 313 + .sub_vendor_id = "IMX", 314 + }; 315 + module_scmi_protocol(scmi_imx_misc); 316 + 317 + MODULE_DESCRIPTION("i.MX SCMI MISC driver"); 318 + MODULE_LICENSE("GPL");
+886
drivers/firmware/arm_scmi/vendors/imx/imx95.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + .. include:: <isonum.txt> 3 + 4 + =============================================================================== 5 + i.MX95 System Control and Management Interface(SCMI) Vendor Protocols Extension 6 + =============================================================================== 7 + 8 + :Copyright: |copy| 2024 NXP 9 + 10 + :Author: Peng Fan <peng.fan@nxp.com> 11 + 12 + The System Manager (SM) is a low-level system function which runs on a System 13 + Control Processor (SCP) to support isolation and management of power domains, 14 + clocks, resets, sensors, pins, etc. on complex application processors. It often 15 + runs on a Cortex-M processor and provides an abstraction to many of the 16 + underlying features of the hardware. The primary purpose of the SM is to allow 17 + isolation between software running on different cores in the SoC. It does this 18 + by having exclusive access to critical resources such as those controlling 19 + power, clocks, reset, PMIC, etc. and then providing an RPC interface to those 20 + clients. This allows the SM to provide access control, arbitration, and 21 + aggregation policies for those shared critical resources. 22 + 23 + SM introduces a concept Logic Machine(LM) which is analogous to VM and each has 24 + its own instance of SCMI. All normal SCMI calls only apply to that LM. That 25 + includes boot, shutdown, reset, suspend, wake, etc. Each LM (e.g. A55 and M7) 26 + are completely isolated from the others and each LM has its own communication 27 + channels talking to the same SCMI server. 28 + 29 + This document covers all the information necessary to understand, maintain, 30 + port, and deploy the SM on supported processors. 31 + 32 + The SM implements an interface compliant with the Arm SCMI Specification 33 + with additional vendor specific extensions. 34 + 35 + SCMI_BBM: System Control and Management BBM Vendor Protocol 36 + ============================================================== 37 + 38 + This protocol is intended provide access to the battery-backed module. This 39 + contains persistent storage (GPR), an RTC, and the ON/OFF button. The protocol 40 + can also provide access to similar functions implemented via external board 41 + components. The BBM protocol provides functions to: 42 + 43 + - Describe the protocol version. 44 + - Discover implementation attributes. 45 + - Read/write GPR 46 + - Discover the RTCs available in the system. 47 + - Read/write the RTC time in seconds and ticks 48 + - Set an alarm (per LM) in seconds 49 + - Get notifications on RTC update, alarm, or rollover. 50 + - Get notification on ON/OFF button activity. 51 + 52 + For most SoC, there is one on-chip RTC (e.g. in BBNSM) and this is RTC ID 0. 53 + Board code can add additional GPR and RTC. 54 + 55 + GPR are not aggregated. The RTC time is also not aggregated. Setting these 56 + sets for all so normally exclusive access would be granted to one agent for 57 + each. However, RTC alarms are maintained for each LM and the hardware is 58 + programmed with the next nearest alarm time. So only one agent in an LM should 59 + be given access rights to set an RTC alarm. 60 + 61 + Commands: 62 + _________ 63 + 64 + PROTOCOL_VERSION 65 + ~~~~~~~~~~~~~~~~ 66 + 67 + message_id: 0x0 68 + protocol_id: 0x81 69 + 70 + +---------------+--------------------------------------------------------------+ 71 + |Return values | 72 + +---------------+--------------------------------------------------------------+ 73 + |Name |Description | 74 + +---------------+--------------------------------------------------------------+ 75 + |int32 status | See ARM SCMI Specification for status code definitions. | 76 + +---------------+--------------------------------------------------------------+ 77 + |uint32 version | For this revision of the specification, this value must be | 78 + | | 0x10000. | 79 + +---------------+--------------------------------------------------------------+ 80 + 81 + PROTOCOL_ATTRIBUTES 82 + ~~~~~~~~~~~~~~~~~~~ 83 + 84 + message_id: 0x1 85 + protocol_id: 0x81 86 + 87 + +---------------+--------------------------------------------------------------+ 88 + |Return values | 89 + +------------------+-----------------------------------------------------------+ 90 + |Name |Description | 91 + +------------------+-----------------------------------------------------------+ 92 + |int32 status | See ARM SCMI Specification for status code definitions. | 93 + +------------------+-----------------------------------------------------------+ 94 + |uint32 attributes | Bits[31:8] Number of RTCs. | 95 + | | Bits[15:0] Number of persistent storage (GPR) words. | 96 + +------------------+-----------------------------------------------------------+ 97 + 98 + PROTOCOL_MESSAGE_ATTRIBUTES 99 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 100 + 101 + message_id: 0x2 102 + protocol_id: 0x81 103 + 104 + +---------------+--------------------------------------------------------------+ 105 + |Return values | 106 + +------------------+-----------------------------------------------------------+ 107 + |Name |Description | 108 + +------------------+-----------------------------------------------------------+ 109 + |int32 status |SUCCESS: in case the message is implemented and available | 110 + | |to use. | 111 + | |NOT_FOUND: if the message identified by message_id is | 112 + | |invalid or not implemented | 113 + +------------------+-----------------------------------------------------------+ 114 + |uint32 attributes |Flags that are associated with a specific function in the | 115 + | |protocol. For all functions in this protocol, this | 116 + | |parameter has a value of 0 | 117 + +------------------+-----------------------------------------------------------+ 118 + 119 + BBM_GPR_SET 120 + ~~~~~~~~~~~ 121 + 122 + message_id: 0x3 123 + protocol_id: 0x81 124 + 125 + +------------------+-----------------------------------------------------------+ 126 + |Parameters | 127 + +------------------+-----------------------------------------------------------+ 128 + |Name |Description | 129 + +------------------+-----------------------------------------------------------+ 130 + |uint32 index |Index of GPR to write | 131 + +------------------+-----------------------------------------------------------+ 132 + |uint32 value |32-bit value to write to the GPR | 133 + +------------------+-----------------------------------------------------------+ 134 + |Return values | 135 + +------------------+-----------------------------------------------------------+ 136 + |Name |Description | 137 + +------------------+-----------------------------------------------------------+ 138 + |int32 status |SUCCESS: if the GPR was successfully written. | 139 + | |NOT_FOUND: if the index is not valid. | 140 + | |DENIED: if the agent does not have permission to write | 141 + | |the specified GPR | 142 + +------------------+-----------------------------------------------------------+ 143 + 144 + BBM_GPR_GET 145 + ~~~~~~~~~~~ 146 + 147 + message_id: 0x4 148 + protocol_id: 0x81 149 + 150 + +------------------+-----------------------------------------------------------+ 151 + |Parameters | 152 + +------------------+-----------------------------------------------------------+ 153 + |Name |Description | 154 + +------------------+-----------------------------------------------------------+ 155 + |uint32 index |Index of GPR to read | 156 + +------------------+-----------------------------------------------------------+ 157 + |Return values | 158 + +------------------+-----------------------------------------------------------+ 159 + |Name |Description | 160 + +------------------+-----------------------------------------------------------+ 161 + |int32 status |SUCCESS: if the GPR was successfully read. | 162 + | |NOT_FOUND: if the index is not valid. | 163 + | |DENIED: if the agent does not have permission to read | 164 + | |the specified GPR. | 165 + +------------------+-----------------------------------------------------------+ 166 + |uint32 value |32-bit value read from the GPR | 167 + +------------------+-----------------------------------------------------------+ 168 + 169 + BBM_RTC_ATTRIBUTES 170 + ~~~~~~~~~~~~~~~~~~ 171 + 172 + message_id: 0x5 173 + protocol_id: 0x81 174 + 175 + +------------------+-----------------------------------------------------------+ 176 + |Parameters | 177 + +------------------+-----------------------------------------------------------+ 178 + |Name |Description | 179 + +------------------+-----------------------------------------------------------+ 180 + |uint32 index |Index of RTC | 181 + +------------------+-----------------------------------------------------------+ 182 + |Return values | 183 + +------------------+-----------------------------------------------------------+ 184 + |Name |Description | 185 + +------------------+-----------------------------------------------------------+ 186 + |int32 status |SUCCESS: returned the attributes. | 187 + | |NOT_FOUND: Index is invalid. | 188 + +------------------+-----------------------------------------------------------+ 189 + |uint32 attributes |Bit[31:24] Bit width of RTC seconds. | 190 + | |Bit[23:16] Bit width of RTC ticks. | 191 + | |Bits[15:0] RTC ticks per second | 192 + +------------------+-----------------------------------------------------------+ 193 + |uint8 name[16] |Null-terminated ASCII string of up to 16 bytes in length | 194 + | |describing the RTC name | 195 + +------------------+-----------------------------------------------------------+ 196 + 197 + BBM_RTC_TIME_SET 198 + ~~~~~~~~~~~~~~~~ 199 + 200 + message_id: 0x6 201 + protocol_id: 0x81 202 + 203 + +------------------+-----------------------------------------------------------+ 204 + |Parameters | 205 + +------------------+-----------------------------------------------------------+ 206 + |Name |Description | 207 + +------------------+-----------------------------------------------------------+ 208 + |uint32 index |Index of RTC | 209 + +------------------+-----------------------------------------------------------+ 210 + |uint32 flags |Bits[31:1] Reserved, must be zero. | 211 + | |Bit[0] RTC time format: | 212 + | |Set to 1 if the time is in ticks. | 213 + | |Set to 0 if the time is in seconds | 214 + +------------------+-----------------------------------------------------------+ 215 + |uint32 time[2] |Lower word: Lower 32 bits of the time in seconds/ticks. | 216 + | |Upper word: Upper 32 bits of the time in seconds/ticks. | 217 + +------------------+-----------------------------------------------------------+ 218 + |Return values | 219 + +------------------+-----------------------------------------------------------+ 220 + |Name |Description | 221 + +------------------+-----------------------------------------------------------+ 222 + |int32 status |SUCCESS: RTC time was successfully set. | 223 + | |NOT_FOUND: rtcId pertains to a non-existent RTC. | 224 + | |INVALID_PARAMETERS: time is not valid | 225 + | |(beyond the range of the RTC). | 226 + | |DENIED: the agent does not have permission to set the RTC. | 227 + +------------------+-----------------------------------------------------------+ 228 + 229 + BBM_RTC_TIME_GET 230 + ~~~~~~~~~~~~~~~~ 231 + 232 + message_id: 0x7 233 + protocol_id: 0x81 234 + 235 + +------------------+-----------------------------------------------------------+ 236 + |Parameters | 237 + +------------------+-----------------------------------------------------------+ 238 + |Name |Description | 239 + +------------------+-----------------------------------------------------------+ 240 + |uint32 index |Index of RTC | 241 + +------------------+-----------------------------------------------------------+ 242 + |uint32 flags |Bits[31:1] Reserved, must be zero. | 243 + | |Bit[0] RTC time format: | 244 + | |Set to 1 if the time is in ticks. | 245 + | |Set to 0 if the time is in seconds | 246 + +------------------+-----------------------------------------------------------+ 247 + |Return values | 248 + +------------------+-----------------------------------------------------------+ 249 + |Name |Description | 250 + +------------------+-----------------------------------------------------------+ 251 + |int32 status |SUCCESS: RTC time was successfully get. | 252 + | |NOT_FOUND: rtcId pertains to a non-existent RTC. | 253 + +------------------+-----------------------------------------------------------+ 254 + |uint32 time[2] |Lower word: Lower 32 bits of the time in seconds/ticks. | 255 + | |Upper word: Upper 32 bits of the time in seconds/ticks. | 256 + +------------------+-----------------------------------------------------------+ 257 + 258 + BBM_RTC_ALARM_SET 259 + ~~~~~~~~~~~~~~~~~ 260 + 261 + message_id: 0x8 262 + protocol_id: 0x81 263 + 264 + +------------------+-----------------------------------------------------------+ 265 + |Parameters | 266 + +------------------+-----------------------------------------------------------+ 267 + |Name |Description | 268 + +------------------+-----------------------------------------------------------+ 269 + |uint32 index |Index of RTC | 270 + +------------------+-----------------------------------------------------------+ 271 + |uint32 flags |Bits[31:1] Reserved, must be zero. | 272 + | |Bit[0] RTC enable flag: | 273 + | |Set to 1 if the RTC alarm should be enabled. | 274 + | |Set to 0 if the RTC alarm should be disabled | 275 + +------------------+-----------------------------------------------------------+ 276 + |uint32 time[2] |Lower word: Lower 32 bits of the time in seconds. | 277 + | |Upper word: Upper 32 bits of the time in seconds. | 278 + +------------------+-----------------------------------------------------------+ 279 + |Return values | 280 + +------------------+-----------------------------------------------------------+ 281 + |Name |Description | 282 + +------------------+-----------------------------------------------------------+ 283 + |int32 status |SUCCESS: RTC time was successfully set. | 284 + | |NOT_FOUND: rtcId pertains to a non-existent RTC. | 285 + | |INVALID_PARAMETERS: time is not valid | 286 + | |(beyond the range of the RTC). | 287 + | |DENIED: the agent does not have permission to set the RTC | 288 + | |alarm | 289 + +------------------+-----------------------------------------------------------+ 290 + 291 + BBM_BUTTON_GET 292 + ~~~~~~~~~~~~~~ 293 + 294 + message_id: 0x9 295 + protocol_id: 0x81 296 + 297 + +------------------+-----------------------------------------------------------+ 298 + |Return values | 299 + +------------------+-----------------------------------------------------------+ 300 + |Name |Description | 301 + +------------------+-----------------------------------------------------------+ 302 + |int32 status |SUCCESS: if the button status was read. | 303 + | |Other value: ARM SCMI Specification status code definitions| 304 + +------------------+-----------------------------------------------------------+ 305 + |uint32 state |State of the ON/OFF button. 1: ON, 0: OFF | 306 + +------------------+-----------------------------------------------------------+ 307 + 308 + BBM_RTC_NOTIFY 309 + ~~~~~~~~~~~~~~ 310 + 311 + message_id: 0xA 312 + protocol_id: 0x81 313 + 314 + +------------------+-----------------------------------------------------------+ 315 + |Parameters | 316 + +------------------+-----------------------------------------------------------+ 317 + |Name |Description | 318 + +------------------+-----------------------------------------------------------+ 319 + |uint32 index |Index of RTC | 320 + +------------------+-----------------------------------------------------------+ 321 + |uint32 flags |Notification flags | 322 + | |Bits[31:3] Reserved, must be zero. | 323 + | |Bit[2] Update enable: | 324 + | |Set to 1 to send notification. | 325 + | |Set to 0 if no notification. | 326 + | |Bit[1] Rollover enable: | 327 + | |Set to 1 to send notification. | 328 + | |Set to 0 if no notification. | 329 + | |Bit[0] Alarm enable: | 330 + | |Set to 1 to send notification. | 331 + | |Set to 0 if no notification | 332 + +------------------+-----------------------------------------------------------+ 333 + |Return values | 334 + +------------------+-----------------------------------------------------------+ 335 + |Name |Description | 336 + +------------------+-----------------------------------------------------------+ 337 + |int32 status |SUCCESS: notification configuration was successfully | 338 + | |updated. | 339 + | |NOT_FOUND: rtcId pertains to a non-existent RTC. | 340 + | |DENIED: the agent does not have permission to request RTC | 341 + | |notifications. | 342 + +------------------+-----------------------------------------------------------+ 343 + 344 + BBM_BUTTON_NOTIFY 345 + ~~~~~~~~~~~~~~~~~ 346 + 347 + message_id: 0xB 348 + protocol_id: 0x81 349 + 350 + +------------------+-----------------------------------------------------------+ 351 + |Parameters | 352 + +------------------+-----------------------------------------------------------+ 353 + |Name |Description | 354 + +------------------+-----------------------------------------------------------+ 355 + |uint32 flags |Notification flags | 356 + | |Bits[31:1] Reserved, must be zero. | 357 + | |Bit[0] Enable button: | 358 + | |Set to 1 to send notification. | 359 + | |Set to 0 if no notification | 360 + +------------------+-----------------------------------------------------------+ 361 + |Return values | 362 + +------------------+-----------------------------------------------------------+ 363 + |Name |Description | 364 + +------------------+-----------------------------------------------------------+ 365 + |int32 status |SUCCESS: notification configuration was successfully | 366 + | |updated. | 367 + | |DENIED: the agent does not have permission to request | 368 + | |button notifications. | 369 + +------------------+-----------------------------------------------------------+ 370 + 371 + NEGOTIATE_PROTOCOL_VERSION 372 + ~~~~~~~~~~~~~~~~~~~~~~~~~~ 373 + 374 + message_id: 0x10 375 + protocol_id: 0x81 376 + 377 + +--------------------+---------------------------------------------------------+ 378 + |Parameters | 379 + +--------------------+---------------------------------------------------------+ 380 + |Name |Description | 381 + +--------------------+---------------------------------------------------------+ 382 + |uint32 version |The negotiated protocol version the agent intends to use | 383 + +--------------------+---------------------------------------------------------+ 384 + |Return values | 385 + +--------------------+---------------------------------------------------------+ 386 + |Name |Description | 387 + +--------------------+---------------------------------------------------------+ 388 + |int32 status |SUCCESS: if the negotiated protocol version is supported | 389 + | |by the platform. All commands, responses, and | 390 + | |notifications post successful return of this command must| 391 + | |comply with the negotiated version. | 392 + | |NOT_SUPPORTED: if the protocol version is not supported. | 393 + +--------------------+---------------------------------------------------------+ 394 + 395 + Notifications 396 + _____________ 397 + 398 + BBM_RTC_EVENT 399 + ~~~~~~~~~~~~~ 400 + 401 + message_id: 0x0 402 + protocol_id: 0x81 403 + 404 + +------------------+-----------------------------------------------------------+ 405 + |Parameters | 406 + +------------------+-----------------------------------------------------------+ 407 + |Name |Description | 408 + +------------------+-----------------------------------------------------------+ 409 + |uint32 flags |RTC events: | 410 + | |Bits[31:2] Reserved, must be zero. | 411 + | |Bit[1] RTC rollover notification: | 412 + | |1 RTC rollover detected. | 413 + | |0 no RTC rollover detected. | 414 + | |Bit[0] RTC alarm notification: | 415 + | |1 RTC alarm generated. | 416 + | |0 no RTC alarm generated. | 417 + +------------------+-----------------------------------------------------------+ 418 + 419 + BBM_BUTTON_EVENT 420 + ~~~~~~~~~~~~~~~~ 421 + 422 + message_id: 0x1 423 + protocol_id: 0x81 424 + 425 + +------------------+-----------------------------------------------------------+ 426 + |Parameters | 427 + +------------------+-----------------------------------------------------------+ 428 + |Name |Description | 429 + +------------------+-----------------------------------------------------------+ 430 + |uint32 flags |RTC events: | 431 + +------------------+-----------------------------------------------------------+ 432 + | |Button events: | 433 + | |Bits[31:1] Reserved, must be zero. | 434 + | |Bit[0] Button notification: | 435 + | |1 button change detected. | 436 + | |0 no button change detected. | 437 + +------------------+-----------------------------------------------------------+ 438 + 439 + SCMI_MISC: System Control and Management MISC Vendor Protocol 440 + ================================================================ 441 + 442 + Provides miscellaneous functions. This includes controls that are miscellaneous 443 + settings/actions that must be exposed from the SM to agents. They are device 444 + specific and are usually define to access bit fields in various mix block 445 + control modules, IOMUX_GPR, and other GPR/CSR owned by the SM. This protocol 446 + supports the following functions: 447 + 448 + - Describe the protocol version. 449 + - Discover implementation attributes. 450 + - Set/Get a control. 451 + - Initiate an action on a control. 452 + - Obtain platform (i.e. SM) build information. 453 + - Obtain ROM passover data. 454 + - Read boot/shutdown/reset information for the LM or the system. 455 + 456 + Commands: 457 + _________ 458 + 459 + PROTOCOL_VERSION 460 + ~~~~~~~~~~~~~~~~ 461 + 462 + message_id: 0x0 463 + protocol_id: 0x84 464 + 465 + +---------------+--------------------------------------------------------------+ 466 + |Return values | 467 + +---------------+--------------------------------------------------------------+ 468 + |Name |Description | 469 + +---------------+--------------------------------------------------------------+ 470 + |int32 status | See ARM SCMI Specification for status code definitions. | 471 + +---------------+--------------------------------------------------------------+ 472 + |uint32 version | For this revision of the specification, this value must be | 473 + | | 0x10000. | 474 + +---------------+--------------------------------------------------------------+ 475 + 476 + PROTOCOL_ATTRIBUTES 477 + ~~~~~~~~~~~~~~~~~~~ 478 + 479 + message_id: 0x1 480 + protocol_id: 0x84 481 + 482 + +------------------+-----------------------------------------------------------+ 483 + |Return values | 484 + +------------------+-----------------------------------------------------------+ 485 + |Name |Description | 486 + +------------------+-----------------------------------------------------------+ 487 + |int32 status | See ARM SCMI Specification for status code definitions. | 488 + +------------------+-----------------------------------------------------------+ 489 + |uint32 attributes |Protocol attributes: | 490 + | |Bits[31:24] Reserved, must be zero. | 491 + | |Bits[23:16] Number of reset reasons. | 492 + | |Bits[15:0] Number of controls | 493 + +------------------+-----------------------------------------------------------+ 494 + 495 + PROTOCOL_MESSAGE_ATTRIBUTES 496 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 497 + 498 + message_id: 0x2 499 + protocol_id: 0x84 500 + 501 + +------------------+-----------------------------------------------------------+ 502 + |Return values | 503 + +------------------+-----------------------------------------------------------+ 504 + |Name |Description | 505 + +------------------+-----------------------------------------------------------+ 506 + |int32 status |SUCCESS: in case the message is implemented and available | 507 + | |to use. | 508 + | |NOT_FOUND: if the message identified by message_id is | 509 + | |invalid or not implemented | 510 + +------------------+-----------------------------------------------------------+ 511 + |uint32 attributes |Flags that are associated with a specific function in the | 512 + | |protocol. For all functions in this protocol, this | 513 + | |parameter has a value of 0 | 514 + +------------------+-----------------------------------------------------------+ 515 + 516 + MISC_CONTROL_SET 517 + ~~~~~~~~~~~~~~~~ 518 + 519 + message_id: 0x3 520 + protocol_id: 0x84 521 + 522 + +------------------+-----------------------------------------------------------+ 523 + |Parameters | 524 + +------------------+-----------------------------------------------------------+ 525 + |Name |Description | 526 + +------------------+-----------------------------------------------------------+ 527 + |uint32 index |Index of the control | 528 + +------------------+-----------------------------------------------------------+ 529 + |uint32 num |Size of the value data in words | 530 + +------------------+-----------------------------------------------------------+ 531 + |uint32 val[8] |value data array | 532 + +------------------+-----------------------------------------------------------+ 533 + |Return values | 534 + +------------------+-----------------------------------------------------------+ 535 + |Name |Description | 536 + +------------------+-----------------------------------------------------------+ 537 + |int32 status |SUCCESS: if the control was set successfully. | 538 + | |NOT_FOUND: if the index is not valid. | 539 + | |DENIED: if the agent does not have permission to set the | 540 + | |control | 541 + +------------------+-----------------------------------------------------------+ 542 + 543 + MISC_CONTROL_GET 544 + ~~~~~~~~~~~~~~~~ 545 + 546 + message_id: 0x4 547 + protocol_id: 0x84 548 + 549 + +------------------+-----------------------------------------------------------+ 550 + |Parameters | 551 + +------------------+-----------------------------------------------------------+ 552 + |Name |Description | 553 + +------------------+-----------------------------------------------------------+ 554 + |uint32 index |Index of the control | 555 + +------------------+-----------------------------------------------------------+ 556 + |Return values | 557 + +------------------+-----------------------------------------------------------+ 558 + |Name |Description | 559 + +------------------+-----------------------------------------------------------+ 560 + |int32 status |SUCCESS: if the control was get successfully. | 561 + | |NOT_FOUND: if the index is not valid. | 562 + | |DENIED: if the agent does not have permission to get the | 563 + | |control | 564 + +------------------+-----------------------------------------------------------+ 565 + |uint32 num |Size of the return data in words, max 8 | 566 + +------------------+-----------------------------------------------------------+ 567 + |uint32 | | 568 + |val[0, num - 1] |value data array | 569 + +------------------+-----------------------------------------------------------+ 570 + 571 + MISC_CONTROL_ACTION 572 + ~~~~~~~~~~~~~~~~~~~ 573 + 574 + message_id: 0x5 575 + protocol_id: 0x84 576 + 577 + +------------------+-----------------------------------------------------------+ 578 + |Parameters | 579 + +------------------+-----------------------------------------------------------+ 580 + |Name |Description | 581 + +------------------+-----------------------------------------------------------+ 582 + |uint32 index |Index of the control | 583 + +------------------+-----------------------------------------------------------+ 584 + |uint32 action |Action for the control | 585 + +------------------+-----------------------------------------------------------+ 586 + |uint32 numarg |Size of the argument data, max 8 | 587 + +------------------+-----------------------------------------------------------+ 588 + |uint32 | | 589 + |arg[0, numarg -1] |Argument data array | 590 + +------------------+-----------------------------------------------------------+ 591 + |Return values | 592 + +------------------+-----------------------------------------------------------+ 593 + |Name |Description | 594 + +------------------+-----------------------------------------------------------+ 595 + |int32 status |SUCCESS: if the action was set successfully. | 596 + | |NOT_FOUND: if the index is not valid. | 597 + | |DENIED: if the agent does not have permission to get the | 598 + | |control | 599 + +------------------+-----------------------------------------------------------+ 600 + |uint32 num |Size of the return data in words, max 8 | 601 + +------------------+-----------------------------------------------------------+ 602 + |uint32 | | 603 + |val[0, num - 1] |value data array | 604 + +------------------+-----------------------------------------------------------+ 605 + 606 + MISC_DISCOVER_BUILD_INFO 607 + ~~~~~~~~~~~~~~~~~~~~~~~~ 608 + 609 + This function is used to obtain the build commit, data, time, number. 610 + 611 + message_id: 0x6 612 + protocol_id: 0x84 613 + 614 + +------------------+-----------------------------------------------------------+ 615 + |Return values | 616 + +------------------+-----------------------------------------------------------+ 617 + |Name |Description | 618 + +------------------+-----------------------------------------------------------+ 619 + |int32 status |SUCCESS: if the build info was got successfully. | 620 + | |NOT_SUPPORTED: if the data is not available. | 621 + +------------------+-----------------------------------------------------------+ 622 + |uint32 buildnum |Build number | 623 + +------------------+-----------------------------------------------------------+ 624 + |uint32 buildcommit|Most significant 32 bits of the git commit hash | 625 + +------------------+-----------------------------------------------------------+ 626 + |uint8 date[16] |Date of build. Null terminated ASCII string of up to 16 | 627 + | |bytes in length | 628 + +------------------+-----------------------------------------------------------+ 629 + |uint8 time[16] |Time of build. Null terminated ASCII string of up to 16 | 630 + | |bytes in length | 631 + +------------------+-----------------------------------------------------------+ 632 + 633 + MISC_ROM_PASSOVER_GET 634 + ~~~~~~~~~~~~~~~~~~~~~ 635 + 636 + ROM passover data is information exported by ROM and could be used by others. 637 + It includes boot device, instance, type, mode and etc. This function is used 638 + to obtain the ROM passover data. The returned block of words is structured as 639 + defined in the ROM passover section in the SoC RM. 640 + 641 + message_id: 0x7 642 + protocol_id: 0x84 643 + 644 + +------------------+-----------------------------------------------------------+ 645 + |Return values | 646 + +------------------+-----------------------------------------------------------+ 647 + |Name |Description | 648 + +------------------+-----------------------------------------------------------+ 649 + |int32 status |SUCCESS: if the data was got successfully. | 650 + | |NOT_SUPPORTED: if the data is not available. | 651 + +------------------+-----------------------------------------------------------+ 652 + |uint32 num |Size of the passover data in words, max 13 | 653 + +------------------+-----------------------------------------------------------+ 654 + |uint32 | | 655 + |data[0, num - 1] |Passover data array | 656 + +------------------+-----------------------------------------------------------+ 657 + 658 + MISC_CONTROL_NOTIFY 659 + ~~~~~~~~~~~~~~~~~~~ 660 + 661 + message_id: 0x8 662 + protocol_id: 0x84 663 + 664 + +------------------+-----------------------------------------------------------+ 665 + |Parameters | 666 + +------------------+-----------------------------------------------------------+ 667 + |Name |Description | 668 + +------------------+-----------------------------------------------------------+ 669 + |uint32 index |Index of control | 670 + +------------------+-----------------------------------------------------------+ 671 + |uint32 flags |Notification flags, varies by control | 672 + +------------------+-----------------------------------------------------------+ 673 + |Return values | 674 + +------------------+-----------------------------------------------------------+ 675 + |Name |Description | 676 + +------------------+-----------------------------------------------------------+ 677 + |int32 status |SUCCESS: notification configuration was successfully | 678 + | |updated. | 679 + | |NOT_FOUND: control id not exists. | 680 + | |INVALID_PARAMETERS: if the input attributes flag specifies | 681 + | |unsupported or invalid configurations.. | 682 + | |DENIED: if the calling agent is not permitted to request | 683 + | |the notification. | 684 + +------------------+-----------------------------------------------------------+ 685 + 686 + MISC_RESET_REASON_ATTRIBUTES 687 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 688 + 689 + message_id: 0x9 690 + protocol_id: 0x84 691 + 692 + +------------------+-----------------------------------------------------------+ 693 + |Parameters | 694 + +------------------+-----------------------------------------------------------+ 695 + |Name |Description | 696 + +------------------+-----------------------------------------------------------+ 697 + |uint32 reasonid |Identifier for the reason | 698 + +------------------+-----------------------------------------------------------+ 699 + |Return values | 700 + +------------------+-----------------------------------------------------------+ 701 + |Name |Description | 702 + +------------------+-----------------------------------------------------------+ 703 + |int32 status |SUCCESS: if valid reason attributes are returned | 704 + | |NOT_FOUND: if reasonId pertains to a non-existent reason. | 705 + +------------------+-----------------------------------------------------------+ 706 + |uint32 attributes |Reason attributes. This parameter has the following | 707 + | |format: Bits[31:0] Reserved, must be zero | 708 + | |Bits[15:0] Number of persistent storage (GPR) words. | 709 + +------------------+-----------------------------------------------------------+ 710 + |uint8 name[16] |Null-terminated ASCII string of up to 16 bytes in length | 711 + | |describing the reason | 712 + +------------------+-----------------------------------------------------------+ 713 + 714 + MISC_RESET_REASON_GET 715 + ~~~~~~~~~~~~~~~~~~~~~ 716 + 717 + message_id: 0xA 718 + protocol_id: 0x84 719 + 720 + +--------------------+---------------------------------------------------------+ 721 + |Parameters | 722 + +--------------------+---------------------------------------------------------+ 723 + |Name |Description | 724 + +--------------------+---------------------------------------------------------+ 725 + |uint32 flags |Reason flags. This parameter has the following format: | 726 + | |Bits[31:1] Reserved, must be zero. | 727 + | |Bit[0] System: | 728 + | |Set to 1 to return the system reason. | 729 + | |Set to 0 to return the LM reason | 730 + +--------------------+---------------------------------------------------------+ 731 + |Return values | 732 + +--------------------+---------------------------------------------------------+ 733 + |Name |Description | 734 + +--------------------+---------------------------------------------------------+ 735 + |int32 status |SUCCESS: reset reason return | 736 + +--------------------+---------------------------------------------------------+ 737 + |uint32 bootflags |Boot reason flags. This parameter has the format: | 738 + | |Bits[31] Valid. | 739 + | |Set to 1 if the entire reason is valid. | 740 + | |Set to 0 if the entire reason is not valid. | 741 + | |Bits[30:29] Reserved, must be zero. | 742 + | |Bit[28] Valid origin: | 743 + | |Set to 1 if the origin field is valid. | 744 + | |Set to 0 if the origin field is not valid. | 745 + | |Bits[27:24] Origin. | 746 + | |Bit[23] Valid err ID: | 747 + | |Set to 1 if the error ID field is valid. | 748 + | |Set to 0 if the error ID field is not valid. | 749 + | |Bits[22:8] Error ID. | 750 + | |Bit[7:0] Reason | 751 + +--------------------+---------------------------------------------------------+ 752 + |uint32 shutdownflags|Shutdown reason flags. This parameter has the format: | 753 + | |Bits[31] Valid. | 754 + | |Set to 1 if the entire reason is valid. | 755 + | |Set to 0 if the entire reason is not valid. | 756 + | |Bits[30:29] Number of valid extended info words. | 757 + | |Bit[28] Valid origin: | 758 + | |Set to 1 if the origin field is valid. | 759 + | |Set to 0 if the origin field is not valid. | 760 + | |Bits[27:24] Origin. | 761 + | |Bit[23] Valid err ID: | 762 + | |Set to 1 if the error ID field is valid. | 763 + | |Set to 0 if the error ID field is not valid. | 764 + | |Bits[22:8] Error ID. | 765 + | |Bit[7:0] Reason | 766 + +--------------------+---------------------------------------------------------+ 767 + |uint32 extinfo[8] |Array of extended info words | 768 + +--------------------+---------------------------------------------------------+ 769 + 770 + MISC_SI_INFO_GET 771 + ~~~~~~~~~~~~~~~~ 772 + 773 + message_id: 0xB 774 + protocol_id: 0x84 775 + 776 + +--------------------+---------------------------------------------------------+ 777 + |Return values | 778 + +--------------------+---------------------------------------------------------+ 779 + |Name |Description | 780 + +--------------------+---------------------------------------------------------+ 781 + |int32 status |SUCCESS: silicon info return | 782 + +--------------------+---------------------------------------------------------+ 783 + |uint32 deviceid |Silicon specific device ID | 784 + +--------------------+---------------------------------------------------------+ 785 + |uint32 sirev |Silicon specific revision | 786 + +--------------------+---------------------------------------------------------+ 787 + |uint32 partnum |Silicon specific part number | 788 + +--------------------+---------------------------------------------------------+ 789 + |uint8 siname[16] |Silicon name/revision. Null terminated ASCII string of up| 790 + | |to 16 bytes in length | 791 + +--------------------+---------------------------------------------------------+ 792 + 793 + MISC_CFG_INFO_GET 794 + ~~~~~~~~~~~~~~~~~ 795 + 796 + message_id: 0xC 797 + protocol_id: 0x84 798 + 799 + +--------------------+---------------------------------------------------------+ 800 + |Return values | 801 + +--------------------+---------------------------------------------------------+ 802 + |Name |Description | 803 + +--------------------+---------------------------------------------------------+ 804 + |int32 status |SUCCESS: config name return | 805 + | |NOT_SUPPORTED: name not available | 806 + +--------------------+---------------------------------------------------------+ 807 + |uint32 msel |Mode selector value | 808 + +--------------------+---------------------------------------------------------+ 809 + |uint8 cfgname[16] |config file basename. Null terminated ASCII string of up | 810 + | |to 16 bytes in length | 811 + +--------------------+---------------------------------------------------------+ 812 + 813 + MISC_SYSLOG_GET 814 + ~~~~~~~~~~~~~~~ 815 + 816 + message_id: 0xD 817 + protocol_id: 0x84 818 + 819 + +--------------------+---------------------------------------------------------+ 820 + |Parameters | 821 + +--------------------+---------------------------------------------------------+ 822 + |Name |Description | 823 + +--------------------+---------------------------------------------------------+ 824 + |uint32 flags |Device specific flags that might impact the data returned| 825 + | |or clearing of the data | 826 + +--------------------+---------------------------------------------------------+ 827 + |uint32 logindex |Index to the first log word. Will be the first element in| 828 + | |the return array | 829 + +--------------------+---------------------------------------------------------+ 830 + |Return values | 831 + +--------------------+---------------------------------------------------------+ 832 + |Name |Description | 833 + +--------------------+---------------------------------------------------------+ 834 + |int32 status |SUCCESS: system log return | 835 + +--------------------+---------------------------------------------------------+ 836 + |uint32 numLogflags |Descriptor for the log data returned by this call. | 837 + | |Bits[31:20] Number of remaining log words. | 838 + | |Bits[15:12] Reserved, must be zero. | 839 + | |Bits[11:0] Number of log words that are returned by this | 840 + | |call | 841 + +--------------------+---------------------------------------------------------+ 842 + |uint32 syslog[N] |Log data array, N is defined in bits[11:0] of numLogflags| 843 + +--------------------+---------------------------------------------------------+ 844 + 845 + NEGOTIATE_PROTOCOL_VERSION 846 + ~~~~~~~~~~~~~~~~~~~~~~~~~~ 847 + 848 + message_id: 0x10 849 + protocol_id: 0x84 850 + 851 + +--------------------+---------------------------------------------------------+ 852 + |Parameters | 853 + +--------------------+---------------------------------------------------------+ 854 + |Name |Description | 855 + +--------------------+---------------------------------------------------------+ 856 + |uint32 version |The negotiated protocol version the agent intends to use | 857 + +--------------------+---------------------------------------------------------+ 858 + |Return values | 859 + +--------------------+---------------------------------------------------------+ 860 + |Name |Description | 861 + +--------------------+---------------------------------------------------------+ 862 + |int32 status |SUCCESS: if the negotiated protocol version is supported | 863 + | |by the platform. All commands, responses, and | 864 + | |notifications post successful return of this command must| 865 + | |comply with the negotiated version. | 866 + | |NOT_SUPPORTED: if the protocol version is not supported. | 867 + +--------------------+---------------------------------------------------------+ 868 + 869 + Notifications 870 + _____________ 871 + 872 + MISC_CONTROL_EVENT 873 + ~~~~~~~~~~~~~~~~~~ 874 + 875 + message_id: 0x0 876 + protocol_id: 0x81 877 + 878 + +------------------+-----------------------------------------------------------+ 879 + |Parameters | 880 + +------------------+-----------------------------------------------------------+ 881 + |Name |Description | 882 + +------------------+-----------------------------------------------------------+ 883 + |uint32 ctrlid |Identifier for the control that caused the event. | 884 + +------------------+-----------------------------------------------------------+ 885 + |uint32 flags |Event flags, varies by control. | 886 + +------------------+-----------------------------------------------------------+
+54 -49
drivers/firmware/arm_scmi/virtio.c drivers/firmware/arm_scmi/transports/virtio.c
··· 4 4 * (SCMI). 5 5 * 6 6 * Copyright (C) 2020-2022 OpenSynergy. 7 - * Copyright (C) 2021-2022 ARM Ltd. 7 + * Copyright (C) 2021-2024 ARM Ltd. 8 8 */ 9 9 10 10 /** ··· 19 19 20 20 #include <linux/completion.h> 21 21 #include <linux/errno.h> 22 + #include <linux/platform_device.h> 22 23 #include <linux/refcount.h> 23 24 #include <linux/slab.h> 24 25 #include <linux/virtio.h> ··· 28 27 #include <uapi/linux/virtio_ids.h> 29 28 #include <uapi/linux/virtio_scmi.h> 30 29 31 - #include "common.h" 30 + #include "../common.h" 32 31 33 32 #define VIRTIO_MAX_RX_TIMEOUT_MS 60000 34 33 #define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */ ··· 108 107 spinlock_t poll_lock; 109 108 refcount_t users; 110 109 }; 110 + 111 + static struct scmi_transport_core_operations *core; 111 112 112 113 /* Only one SCMI VirtIO device can possibly exist */ 113 114 static struct virtio_device *scmi_vdev; ··· 297 294 298 295 if (msg) { 299 296 msg->rx_len = length; 300 - scmi_rx_callback(vioch->cinfo, 301 - msg_read_header(msg->input), msg); 297 + core->rx_callback(vioch->cinfo, 298 + core->msg->read_header(msg->input), 299 + msg); 302 300 303 301 scmi_finalize_message(vioch, msg); 304 302 } ··· 343 339 * is no more processed elsewhere so no poll_lock needed. 344 340 */ 345 341 if (msg->poll_status == VIO_MSG_NOT_POLLED) 346 - scmi_rx_callback(vioch->cinfo, 347 - msg_read_header(msg->input), msg); 342 + core->rx_callback(vioch->cinfo, 343 + core->msg->read_header(msg->input), 344 + msg); 348 345 349 346 /* Free the processed message once done */ 350 347 scmi_vio_msg_release(vioch, msg); ··· 369 364 struct scmi_vio_channel *vioch = base_cinfo->transport_info; 370 365 371 366 return vioch->max_msg; 372 - } 373 - 374 - static int virtio_link_supplier(struct device *dev) 375 - { 376 - if (!scmi_vdev) { 377 - dev_notice(dev, 378 - "Deferring probe after not finding a bound scmi-virtio device\n"); 379 - return -EPROBE_DEFER; 380 - } 381 - 382 - if (!device_link_add(dev, &scmi_vdev->dev, 383 - DL_FLAG_AUTOREMOVE_CONSUMER)) { 384 - dev_err(dev, "Adding link to supplier virtio device failed\n"); 385 - return -ECANCELED; 386 - } 387 - 388 - return 0; 389 367 } 390 368 391 369 static bool virtio_chan_available(struct device_node *of_node, int idx) ··· 498 510 return -EBUSY; 499 511 } 500 512 501 - msg_tx_prepare(msg->request, xfer); 513 + core->msg->tx_prepare(msg->request, xfer); 502 514 503 - sg_init_one(&sg_out, msg->request, msg_command_size(xfer)); 504 - sg_init_one(&sg_in, msg->input, msg_response_size(xfer)); 515 + sg_init_one(&sg_out, msg->request, core->msg->command_size(xfer)); 516 + sg_init_one(&sg_in, msg->input, core->msg->response_size(xfer)); 505 517 506 518 spin_lock_irqsave(&vioch->lock, flags); 507 519 ··· 548 560 struct scmi_vio_msg *msg = xfer->priv; 549 561 550 562 if (msg) 551 - msg_fetch_response(msg->input, msg->rx_len, xfer); 563 + core->msg->fetch_response(msg->input, msg->rx_len, xfer); 552 564 } 553 565 554 566 static void virtio_fetch_notification(struct scmi_chan_info *cinfo, ··· 557 569 struct scmi_vio_msg *msg = xfer->priv; 558 570 559 571 if (msg) 560 - msg_fetch_notification(msg->input, msg->rx_len, max_len, xfer); 572 + core->msg->fetch_notification(msg->input, msg->rx_len, 573 + max_len, xfer); 561 574 } 562 575 563 576 /** ··· 658 669 * the message we are polling for could be alternatively delivered via usual 659 670 * IRQs callbacks on another core which happened to have IRQs enabled while we 660 671 * are actively polling for it here: in such a case it will be handled as such 661 - * by scmi_rx_callback() and the polling loop in the SCMI Core TX path will be 672 + * by rx_callback() and the polling loop in the SCMI Core TX path will be 662 673 * transparently terminated anyway. 663 674 * 664 675 * Return: True once polling has successfully completed. ··· 779 790 } 780 791 781 792 static const struct scmi_transport_ops scmi_virtio_ops = { 782 - .link_supplier = virtio_link_supplier, 783 793 .chan_available = virtio_chan_available, 784 794 .chan_setup = virtio_chan_setup, 785 795 .chan_free = virtio_chan_free, ··· 789 801 .mark_txdone = virtio_mark_txdone, 790 802 .poll_done = virtio_poll_done, 791 803 }; 804 + 805 + static struct scmi_desc scmi_virtio_desc = { 806 + .ops = &scmi_virtio_ops, 807 + /* for non-realtime virtio devices */ 808 + .max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS, 809 + .max_msg = 0, /* overridden by virtio_get_max_msg() */ 810 + .max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE, 811 + .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE), 812 + }; 813 + 814 + static const struct of_device_id scmi_of_match[] = { 815 + { .compatible = "arm,scmi-virtio" }, 816 + { /* Sentinel */ }, 817 + }; 818 + 819 + DEFINE_SCMI_TRANSPORT_DRIVER(scmi_virtio, scmi_virtio_driver, scmi_virtio_desc, 820 + scmi_of_match, core); 792 821 793 822 static int scmi_vio_probe(struct virtio_device *vdev) 794 823 { ··· 866 861 } 867 862 868 863 vdev->priv = channels; 864 + 869 865 /* Ensure initialized scmi_vdev is visible */ 870 866 smp_store_mb(scmi_vdev, vdev); 867 + 868 + ret = platform_driver_register(&scmi_virtio_driver); 869 + if (ret) { 870 + vdev->priv = NULL; 871 + vdev->config->del_vqs(vdev); 872 + /* Ensure NULLified scmi_vdev is visible */ 873 + smp_store_mb(scmi_vdev, NULL); 874 + 875 + return ret; 876 + } 871 877 872 878 return 0; 873 879 } 874 880 875 881 static void scmi_vio_remove(struct virtio_device *vdev) 876 882 { 883 + platform_driver_unregister(&scmi_virtio_driver); 884 + 877 885 /* 878 886 * Once we get here, virtio_chan_free() will have already been called by 879 887 * the SCMI core for any existing channel and, as a consequence, all the ··· 931 913 .validate = scmi_vio_validate, 932 914 }; 933 915 934 - static int __init virtio_scmi_init(void) 935 - { 936 - return register_virtio_driver(&virtio_scmi_driver); 937 - } 916 + module_virtio_driver(virtio_scmi_driver); 938 917 939 - static void virtio_scmi_exit(void) 940 - { 941 - unregister_virtio_driver(&virtio_scmi_driver); 942 - } 943 - 944 - const struct scmi_desc scmi_virtio_desc = { 945 - .transport_init = virtio_scmi_init, 946 - .transport_exit = virtio_scmi_exit, 947 - .ops = &scmi_virtio_ops, 948 - /* for non-realtime virtio devices */ 949 - .max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS, 950 - .max_msg = 0, /* overridden by virtio_get_max_msg() */ 951 - .max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE, 952 - .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE), 953 - }; 918 + MODULE_AUTHOR("Igor Skalkin <igor.skalkin@opensynergy.com>"); 919 + MODULE_AUTHOR("Peter Hilber <peter.hilber@opensynergy.com>"); 920 + MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>"); 921 + MODULE_DESCRIPTION("SCMI VirtIO Transport driver"); 922 + MODULE_LICENSE("GPL");
+4 -2
drivers/firmware/arm_scmi/voltage.c
··· 11 11 #include "protocols.h" 12 12 13 13 /* Updated only after ALL the mandatory features for that version are merged */ 14 - #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 14 + #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 15 15 16 16 #define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0) 17 17 #define REMAINING_LEVELS_MASK GENMASK(31, 16) ··· 229 229 /* Retrieve domain attributes at first ... */ 230 230 put_unaligned_le32(dom, td->tx.buf); 231 231 /* Skip domain on comms error */ 232 - if (ph->xops->do_xfer(ph, td)) 232 + if (ph->xops->do_xfer(ph, td)) { 233 + ph->xops->reset_rx_to_maxsz(ph, td); 233 234 continue; 235 + } 234 236 235 237 v = vinfo->domains + dom; 236 238 v->id = dom;
+11
drivers/firmware/imx/Kconfig
··· 22 22 23 23 This driver manages the IPC interface between host CPU and the 24 24 SCU firmware running on M4. 25 + 26 + config IMX_SCMI_MISC_DRV 27 + tristate "IMX SCMI MISC Protocol driver" 28 + depends on IMX_SCMI_MISC_EXT || 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 misc functions such as board control. 34 + 35 + This driver can also be built as a module.
+1
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_MISC_DRV} += sm-misc.o
+119
drivers/firmware/imx/sm-misc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright 2024 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_misc_proto_ops *imx_misc_ctrl_ops; 14 + static struct scmi_protocol_handle *ph; 15 + struct notifier_block scmi_imx_misc_ctrl_nb; 16 + 17 + int scmi_imx_misc_ctrl_set(u32 id, u32 val) 18 + { 19 + if (!ph) 20 + return -EPROBE_DEFER; 21 + 22 + return imx_misc_ctrl_ops->misc_ctrl_set(ph, id, 1, &val); 23 + }; 24 + EXPORT_SYMBOL(scmi_imx_misc_ctrl_set); 25 + 26 + int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val) 27 + { 28 + if (!ph) 29 + return -EPROBE_DEFER; 30 + 31 + return imx_misc_ctrl_ops->misc_ctrl_get(ph, id, num, val); 32 + } 33 + EXPORT_SYMBOL(scmi_imx_misc_ctrl_get); 34 + 35 + static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb, 36 + unsigned long event, void *data) 37 + { 38 + /* 39 + * notifier_chain_register requires a valid notifier_block and 40 + * valid notifier_call. SCMI_EVENT_IMX_MISC_CONTROL is needed 41 + * to let SCMI firmware enable control events, but the hook here 42 + * is just a dummy function to avoid kernel panic as of now. 43 + */ 44 + return 0; 45 + } 46 + 47 + static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev) 48 + { 49 + const struct scmi_handle *handle = sdev->handle; 50 + struct device_node *np = sdev->dev.of_node; 51 + u32 src_id, flags; 52 + int ret, i, num; 53 + 54 + if (!handle) 55 + return -ENODEV; 56 + 57 + if (imx_misc_ctrl_ops) { 58 + dev_err(&sdev->dev, "misc ctrl already initialized\n"); 59 + return -EEXIST; 60 + } 61 + 62 + imx_misc_ctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_MISC, &ph); 63 + if (IS_ERR(imx_misc_ctrl_ops)) 64 + return PTR_ERR(imx_misc_ctrl_ops); 65 + 66 + num = of_property_count_u32_elems(np, "nxp,ctrl-ids"); 67 + if (num % 2) { 68 + dev_err(&sdev->dev, "Invalid wakeup-sources\n"); 69 + return -EINVAL; 70 + } 71 + 72 + scmi_imx_misc_ctrl_nb.notifier_call = &scmi_imx_misc_ctrl_notifier; 73 + for (i = 0; i < num; i += 2) { 74 + ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i, &src_id); 75 + if (ret) { 76 + dev_err(&sdev->dev, "Failed to read ctrl-id: %i\n", i); 77 + continue; 78 + } 79 + 80 + ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i + 1, &flags); 81 + if (ret) { 82 + dev_err(&sdev->dev, "Failed to read ctrl-id value: %d\n", i + 1); 83 + continue; 84 + } 85 + 86 + ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_MISC, 87 + SCMI_EVENT_IMX_MISC_CONTROL, 88 + &src_id, 89 + &scmi_imx_misc_ctrl_nb); 90 + if (ret) { 91 + dev_err(&sdev->dev, "Failed to register scmi misc event: %d\n", src_id); 92 + } else { 93 + ret = imx_misc_ctrl_ops->misc_ctrl_req_notify(ph, src_id, 94 + SCMI_EVENT_IMX_MISC_CONTROL, 95 + flags); 96 + if (ret) 97 + dev_err(&sdev->dev, "Failed to req notify: %d\n", src_id); 98 + } 99 + } 100 + 101 + return 0; 102 + } 103 + 104 + static const struct scmi_device_id scmi_id_table[] = { 105 + { SCMI_PROTOCOL_IMX_MISC, "imx-misc-ctrl" }, 106 + { }, 107 + }; 108 + MODULE_DEVICE_TABLE(scmi, scmi_id_table); 109 + 110 + static struct scmi_driver scmi_imx_misc_ctrl_driver = { 111 + .name = "scmi-imx-misc-ctrl", 112 + .probe = scmi_imx_misc_ctrl_probe, 113 + .id_table = scmi_id_table, 114 + }; 115 + module_scmi_driver(scmi_imx_misc_ctrl_driver); 116 + 117 + MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 118 + MODULE_DESCRIPTION("IMX SM MISC driver"); 119 + MODULE_LICENSE("GPL");
+11
drivers/input/keyboard/Kconfig
··· 466 466 To compile this driver as a module, choose M here: the 467 467 module will be called imx_keypad. 468 468 469 + config KEYBOARD_IMX_BBM_SCMI 470 + tristate "IMX BBM SCMI Key Driver" 471 + depends on IMX_SCMI_BBM_EXT || COMPILE_TEST 472 + default y if ARCH_MXC 473 + help 474 + This is the BBM key driver for NXP i.MX SoCs managed through 475 + SCMI protocol. 476 + 477 + To compile this driver as a module, choose M here: the 478 + module will be called scmi-imx-bbm-key. 479 + 469 480 config KEYBOARD_IMX_SC_KEY 470 481 tristate "IMX SCU Key Driver" 471 482 depends on IMX_SCU
+1
drivers/input/keyboard/Makefile
··· 31 31 obj-$(CONFIG_KEYBOARD_IQS62X) += iqs62x-keys.o 32 32 obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o 33 33 obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o 34 + obj-$(CONFIG_KEYBOARD_IMX_BBM_SCMI) += imx-sm-bbm-key.o 34 35 obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o 35 36 obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o 36 37 obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
+225
drivers/input/keyboard/imx-sm-bbm-key.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright 2024 NXP. 4 + */ 5 + 6 + #include <linux/input.h> 7 + #include <linux/jiffies.h> 8 + #include <linux/module.h> 9 + #include <linux/of.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/rtc.h> 12 + #include <linux/scmi_protocol.h> 13 + #include <linux/scmi_imx_protocol.h> 14 + #include <linux/suspend.h> 15 + 16 + #define DEBOUNCE_TIME 30 17 + #define REPEAT_INTERVAL 60 18 + 19 + struct scmi_imx_bbm { 20 + struct scmi_protocol_handle *ph; 21 + const struct scmi_imx_bbm_proto_ops *ops; 22 + struct notifier_block nb; 23 + int keycode; 24 + int keystate; /* 1:pressed */ 25 + bool suspended; 26 + struct delayed_work check_work; 27 + struct input_dev *input; 28 + }; 29 + 30 + static void scmi_imx_bbm_pwrkey_check_for_events(struct work_struct *work) 31 + { 32 + struct scmi_imx_bbm *bbnsm = container_of(to_delayed_work(work), 33 + struct scmi_imx_bbm, check_work); 34 + struct scmi_protocol_handle *ph = bbnsm->ph; 35 + struct input_dev *input = bbnsm->input; 36 + u32 state = 0; 37 + int ret; 38 + 39 + ret = bbnsm->ops->button_get(ph, &state); 40 + if (ret) { 41 + pr_err("%s: %d\n", __func__, ret); 42 + return; 43 + } 44 + 45 + pr_debug("%s: state: %d, keystate %d\n", __func__, state, bbnsm->keystate); 46 + 47 + /* only report new event if status changed */ 48 + if (state ^ bbnsm->keystate) { 49 + bbnsm->keystate = state; 50 + input_event(input, EV_KEY, bbnsm->keycode, state); 51 + input_sync(input); 52 + pm_relax(bbnsm->input->dev.parent); 53 + pr_debug("EV_KEY: %x\n", bbnsm->keycode); 54 + } 55 + 56 + /* repeat check if pressed long */ 57 + if (state) 58 + schedule_delayed_work(&bbnsm->check_work, msecs_to_jiffies(REPEAT_INTERVAL)); 59 + } 60 + 61 + static int scmi_imx_bbm_pwrkey_event(struct scmi_imx_bbm *bbnsm) 62 + { 63 + struct input_dev *input = bbnsm->input; 64 + 65 + pm_wakeup_event(input->dev.parent, 0); 66 + 67 + /* 68 + * Directly report key event after resume to make no key press 69 + * event is missed. 70 + */ 71 + if (READ_ONCE(bbnsm->suspended)) { 72 + bbnsm->keystate = 1; 73 + input_event(input, EV_KEY, bbnsm->keycode, 1); 74 + input_sync(input); 75 + WRITE_ONCE(bbnsm->suspended, false); 76 + } 77 + 78 + schedule_delayed_work(&bbnsm->check_work, msecs_to_jiffies(DEBOUNCE_TIME)); 79 + 80 + return 0; 81 + } 82 + 83 + static void scmi_imx_bbm_pwrkey_act(void *pdata) 84 + { 85 + struct scmi_imx_bbm *bbnsm = pdata; 86 + 87 + cancel_delayed_work_sync(&bbnsm->check_work); 88 + } 89 + 90 + static int scmi_imx_bbm_key_notifier(struct notifier_block *nb, unsigned long event, void *data) 91 + { 92 + struct scmi_imx_bbm *bbnsm = container_of(nb, struct scmi_imx_bbm, nb); 93 + struct scmi_imx_bbm_notif_report *r = data; 94 + 95 + if (r->is_button) { 96 + pr_debug("BBM Button Power key pressed\n"); 97 + scmi_imx_bbm_pwrkey_event(bbnsm); 98 + } else { 99 + /* Should never reach here */ 100 + pr_err("Unexpected BBM event: %s\n", __func__); 101 + } 102 + 103 + return 0; 104 + } 105 + 106 + static int scmi_imx_bbm_pwrkey_init(struct scmi_device *sdev) 107 + { 108 + const struct scmi_handle *handle = sdev->handle; 109 + struct device *dev = &sdev->dev; 110 + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); 111 + struct input_dev *input; 112 + int ret; 113 + 114 + if (device_property_read_u32(dev, "linux,code", &bbnsm->keycode)) { 115 + bbnsm->keycode = KEY_POWER; 116 + dev_warn(dev, "key code is not specified, using default KEY_POWER\n"); 117 + } 118 + 119 + INIT_DELAYED_WORK(&bbnsm->check_work, scmi_imx_bbm_pwrkey_check_for_events); 120 + 121 + input = devm_input_allocate_device(dev); 122 + if (!input) { 123 + dev_err(dev, "failed to allocate the input device for SCMI IMX BBM\n"); 124 + return -ENOMEM; 125 + } 126 + 127 + input->name = dev_name(dev); 128 + input->phys = "bbnsm-pwrkey/input0"; 129 + input->id.bustype = BUS_HOST; 130 + 131 + input_set_capability(input, EV_KEY, bbnsm->keycode); 132 + 133 + ret = devm_add_action_or_reset(dev, scmi_imx_bbm_pwrkey_act, bbnsm); 134 + if (ret) { 135 + dev_err(dev, "failed to register remove action\n"); 136 + return ret; 137 + } 138 + 139 + bbnsm->input = input; 140 + 141 + bbnsm->nb.notifier_call = &scmi_imx_bbm_key_notifier; 142 + ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_BBM, 143 + SCMI_EVENT_IMX_BBM_BUTTON, 144 + NULL, &bbnsm->nb); 145 + 146 + if (ret) 147 + dev_err(dev, "Failed to register BBM Button Events %d:", ret); 148 + 149 + ret = input_register_device(input); 150 + if (ret) { 151 + dev_err(dev, "failed to register input device\n"); 152 + return ret; 153 + } 154 + 155 + return 0; 156 + } 157 + 158 + static int scmi_imx_bbm_key_probe(struct scmi_device *sdev) 159 + { 160 + const struct scmi_handle *handle = sdev->handle; 161 + struct device *dev = &sdev->dev; 162 + struct scmi_protocol_handle *ph; 163 + struct scmi_imx_bbm *bbnsm; 164 + int ret; 165 + 166 + if (!handle) 167 + return -ENODEV; 168 + 169 + bbnsm = devm_kzalloc(dev, sizeof(*bbnsm), GFP_KERNEL); 170 + if (!bbnsm) 171 + return -ENOMEM; 172 + 173 + bbnsm->ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_BBM, &ph); 174 + if (IS_ERR(bbnsm->ops)) 175 + return PTR_ERR(bbnsm->ops); 176 + 177 + bbnsm->ph = ph; 178 + 179 + device_init_wakeup(dev, true); 180 + 181 + dev_set_drvdata(dev, bbnsm); 182 + 183 + ret = scmi_imx_bbm_pwrkey_init(sdev); 184 + if (ret) 185 + device_init_wakeup(dev, false); 186 + 187 + return ret; 188 + } 189 + 190 + static int __maybe_unused scmi_imx_bbm_key_suspend(struct device *dev) 191 + { 192 + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); 193 + 194 + WRITE_ONCE(bbnsm->suspended, true); 195 + 196 + return 0; 197 + } 198 + 199 + static int __maybe_unused scmi_imx_bbm_key_resume(struct device *dev) 200 + { 201 + return 0; 202 + } 203 + 204 + static SIMPLE_DEV_PM_OPS(scmi_imx_bbm_pm_key_ops, scmi_imx_bbm_key_suspend, 205 + scmi_imx_bbm_key_resume); 206 + 207 + static const struct scmi_device_id scmi_id_table[] = { 208 + { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-key" }, 209 + { }, 210 + }; 211 + MODULE_DEVICE_TABLE(scmi, scmi_id_table); 212 + 213 + static struct scmi_driver scmi_imx_bbm_key_driver = { 214 + .driver = { 215 + .pm = &scmi_imx_bbm_pm_key_ops, 216 + }, 217 + .name = "scmi-imx-bbm-key", 218 + .probe = scmi_imx_bbm_key_probe, 219 + .id_table = scmi_id_table, 220 + }; 221 + module_scmi_driver(scmi_imx_bbm_key_driver); 222 + 223 + MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 224 + MODULE_DESCRIPTION("IMX SM BBM Key driver"); 225 + MODULE_LICENSE("GPL");
+11
drivers/rtc/Kconfig
··· 1827 1827 This driver can also be built as a module, if so, the module 1828 1828 will be called "rtc-bbnsm". 1829 1829 1830 + config RTC_DRV_IMX_BBM_SCMI 1831 + depends on IMX_SCMI_BBM_EXT || COMPILE_TEST 1832 + default y if ARCH_MXC 1833 + tristate "NXP i.MX BBM SCMI RTC support" 1834 + help 1835 + If you say yes here you get support for the NXP i.MX BBSM SCMI 1836 + RTC module. 1837 + 1838 + To compile this driver as a module, choose M here: the 1839 + module will be called rtc-imx-sm-bbm. 1840 + 1830 1841 config RTC_DRV_IMX_SC 1831 1842 depends on IMX_SCU 1832 1843 depends on HAVE_ARM_SMCCC
+1
drivers/rtc/Makefile
··· 74 74 obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o 75 75 obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o 76 76 obj-$(CONFIG_RTC_DRV_IMX_SC) += rtc-imx-sc.o 77 + obj-$(CONFIG_RTC_DRV_IMX_BBM_SCMI) += rtc-imx-sm-bbm.o 77 78 obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o 78 79 obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o 79 80 obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
+162
drivers/rtc/rtc-imx-sm-bbm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright 2024 NXP. 4 + */ 5 + 6 + #include <linux/jiffies.h> 7 + #include <linux/module.h> 8 + #include <linux/platform_device.h> 9 + #include <linux/rtc.h> 10 + #include <linux/scmi_protocol.h> 11 + #include <linux/scmi_imx_protocol.h> 12 + 13 + struct scmi_imx_bbm { 14 + const struct scmi_imx_bbm_proto_ops *ops; 15 + struct rtc_device *rtc_dev; 16 + struct scmi_protocol_handle *ph; 17 + struct notifier_block nb; 18 + }; 19 + 20 + static int scmi_imx_bbm_read_time(struct device *dev, struct rtc_time *tm) 21 + { 22 + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); 23 + struct scmi_protocol_handle *ph = bbnsm->ph; 24 + u64 val; 25 + int ret; 26 + 27 + ret = bbnsm->ops->rtc_time_get(ph, 0, &val); 28 + if (ret) 29 + return ret; 30 + 31 + rtc_time64_to_tm(val, tm); 32 + 33 + return 0; 34 + } 35 + 36 + static int scmi_imx_bbm_set_time(struct device *dev, struct rtc_time *tm) 37 + { 38 + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); 39 + struct scmi_protocol_handle *ph = bbnsm->ph; 40 + u64 val; 41 + 42 + val = rtc_tm_to_time64(tm); 43 + 44 + return bbnsm->ops->rtc_time_set(ph, 0, val); 45 + } 46 + 47 + static int scmi_imx_bbm_alarm_irq_enable(struct device *dev, unsigned int enable) 48 + { 49 + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); 50 + struct scmi_protocol_handle *ph = bbnsm->ph; 51 + 52 + /* scmi_imx_bbm_set_alarm enables the irq, just handle disable here */ 53 + if (!enable) 54 + return bbnsm->ops->rtc_alarm_set(ph, 0, false, 0); 55 + 56 + return 0; 57 + } 58 + 59 + static int scmi_imx_bbm_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 60 + { 61 + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); 62 + struct scmi_protocol_handle *ph = bbnsm->ph; 63 + struct rtc_time *alrm_tm = &alrm->time; 64 + u64 val; 65 + 66 + val = rtc_tm_to_time64(alrm_tm); 67 + 68 + return bbnsm->ops->rtc_alarm_set(ph, 0, true, val); 69 + } 70 + 71 + static const struct rtc_class_ops smci_imx_bbm_rtc_ops = { 72 + .read_time = scmi_imx_bbm_read_time, 73 + .set_time = scmi_imx_bbm_set_time, 74 + .set_alarm = scmi_imx_bbm_set_alarm, 75 + .alarm_irq_enable = scmi_imx_bbm_alarm_irq_enable, 76 + }; 77 + 78 + static int scmi_imx_bbm_rtc_notifier(struct notifier_block *nb, unsigned long event, void *data) 79 + { 80 + struct scmi_imx_bbm *bbnsm = container_of(nb, struct scmi_imx_bbm, nb); 81 + struct scmi_imx_bbm_notif_report *r = data; 82 + 83 + if (r->is_rtc) 84 + rtc_update_irq(bbnsm->rtc_dev, 1, RTC_AF | RTC_IRQF); 85 + else 86 + pr_err("Unexpected bbm event: %s\n", __func__); 87 + 88 + return 0; 89 + } 90 + 91 + static int scmi_imx_bbm_rtc_init(struct scmi_device *sdev) 92 + { 93 + const struct scmi_handle *handle = sdev->handle; 94 + struct device *dev = &sdev->dev; 95 + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); 96 + int ret; 97 + 98 + bbnsm->rtc_dev = devm_rtc_allocate_device(dev); 99 + if (IS_ERR(bbnsm->rtc_dev)) 100 + return PTR_ERR(bbnsm->rtc_dev); 101 + 102 + bbnsm->rtc_dev->ops = &smci_imx_bbm_rtc_ops; 103 + bbnsm->rtc_dev->range_max = U32_MAX; 104 + 105 + bbnsm->nb.notifier_call = &scmi_imx_bbm_rtc_notifier; 106 + ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_BBM, 107 + SCMI_EVENT_IMX_BBM_RTC, 108 + NULL, &bbnsm->nb); 109 + if (ret) 110 + return ret; 111 + 112 + return devm_rtc_register_device(bbnsm->rtc_dev); 113 + } 114 + 115 + static int scmi_imx_bbm_rtc_probe(struct scmi_device *sdev) 116 + { 117 + const struct scmi_handle *handle = sdev->handle; 118 + struct device *dev = &sdev->dev; 119 + struct scmi_protocol_handle *ph; 120 + struct scmi_imx_bbm *bbnsm; 121 + int ret; 122 + 123 + if (!handle) 124 + return -ENODEV; 125 + 126 + bbnsm = devm_kzalloc(dev, sizeof(*bbnsm), GFP_KERNEL); 127 + if (!bbnsm) 128 + return -ENOMEM; 129 + 130 + bbnsm->ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_BBM, &ph); 131 + if (IS_ERR(bbnsm->ops)) 132 + return PTR_ERR(bbnsm->ops); 133 + 134 + bbnsm->ph = ph; 135 + 136 + device_init_wakeup(dev, true); 137 + 138 + dev_set_drvdata(dev, bbnsm); 139 + 140 + ret = scmi_imx_bbm_rtc_init(sdev); 141 + if (ret) 142 + device_init_wakeup(dev, false); 143 + 144 + return ret; 145 + } 146 + 147 + static const struct scmi_device_id scmi_id_table[] = { 148 + { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-rtc" }, 149 + { }, 150 + }; 151 + MODULE_DEVICE_TABLE(scmi, scmi_id_table); 152 + 153 + static struct scmi_driver scmi_imx_bbm_rtc_driver = { 154 + .name = "scmi-imx-bbm-rtc", 155 + .probe = scmi_imx_bbm_rtc_probe, 156 + .id_table = scmi_id_table, 157 + }; 158 + module_scmi_driver(scmi_imx_bbm_rtc_driver); 159 + 160 + MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); 161 + MODULE_DESCRIPTION("IMX SM BBM RTC driver"); 162 + MODULE_LICENSE("GPL");
+34
include/linux/firmware/imx/sm.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + /* 3 + * Copyright 2024 NXP 4 + */ 5 + 6 + #ifndef _SCMI_IMX_H 7 + #define _SCMI_IMX_H 8 + 9 + #include <linux/bitfield.h> 10 + #include <linux/errno.h> 11 + #include <linux/types.h> 12 + 13 + #define SCMI_IMX_CTRL_PDM_CLK_SEL 0 /* AON PDM clock sel */ 14 + #define SCMI_IMX_CTRL_MQS1_SETTINGS 1 /* AON MQS settings */ 15 + #define SCMI_IMX_CTRL_SAI1_MCLK 2 /* AON SAI1 MCLK */ 16 + #define SCMI_IMX_CTRL_SAI3_MCLK 3 /* WAKE SAI3 MCLK */ 17 + #define SCMI_IMX_CTRL_SAI4_MCLK 4 /* WAKE SAI4 MCLK */ 18 + #define SCMI_IMX_CTRL_SAI5_MCLK 5 /* WAKE SAI5 MCLK */ 19 + 20 + #if IS_ENABLED(CONFIG_IMX_SCMI_MISC_EXT) 21 + int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val); 22 + int scmi_imx_misc_ctrl_set(u32 id, u32 val); 23 + #else 24 + static inline int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val) 25 + { 26 + return -EOPNOTSUPP; 27 + } 28 + 29 + static inline int scmi_imx_misc_ctrl_set(u32 id, u32 val); 30 + { 31 + return -EOPNOTSUPP; 32 + } 33 + #endif 34 + #endif
+59
include/linux/scmi_imx_protocol.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * SCMI Message Protocol driver NXP extension header 4 + * 5 + * Copyright 2024 NXP. 6 + */ 7 + 8 + #ifndef _LINUX_SCMI_NXP_PROTOCOL_H 9 + #define _LINUX_SCMI_NXP_PROTOCOL_H 10 + 11 + #include <linux/bitfield.h> 12 + #include <linux/device.h> 13 + #include <linux/notifier.h> 14 + #include <linux/types.h> 15 + 16 + enum scmi_nxp_protocol { 17 + SCMI_PROTOCOL_IMX_BBM = 0x81, 18 + SCMI_PROTOCOL_IMX_MISC = 0x84, 19 + }; 20 + 21 + struct scmi_imx_bbm_proto_ops { 22 + int (*rtc_time_set)(const struct scmi_protocol_handle *ph, u32 id, 23 + uint64_t sec); 24 + int (*rtc_time_get)(const struct scmi_protocol_handle *ph, u32 id, 25 + u64 *val); 26 + int (*rtc_alarm_set)(const struct scmi_protocol_handle *ph, u32 id, 27 + bool enable, u64 sec); 28 + int (*button_get)(const struct scmi_protocol_handle *ph, u32 *state); 29 + }; 30 + 31 + enum scmi_nxp_notification_events { 32 + SCMI_EVENT_IMX_BBM_RTC = 0x0, 33 + SCMI_EVENT_IMX_BBM_BUTTON = 0x1, 34 + SCMI_EVENT_IMX_MISC_CONTROL = 0x0, 35 + }; 36 + 37 + struct scmi_imx_bbm_notif_report { 38 + bool is_rtc; 39 + bool is_button; 40 + ktime_t timestamp; 41 + unsigned int rtc_id; 42 + unsigned int rtc_evt; 43 + }; 44 + 45 + struct scmi_imx_misc_ctrl_notify_report { 46 + ktime_t timestamp; 47 + unsigned int ctrl_id; 48 + unsigned int flags; 49 + }; 50 + 51 + struct scmi_imx_misc_proto_ops { 52 + int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 id, 53 + u32 num, u32 *val); 54 + int (*misc_ctrl_get)(const struct scmi_protocol_handle *ph, u32 id, 55 + u32 *num, u32 *val); 56 + int (*misc_ctrl_req_notify)(const struct scmi_protocol_handle *ph, 57 + u32 ctrl_id, u32 evt_id, u32 flags); 58 + }; 59 + #endif