All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Add Altera SoCFPGA Crypto Service (FCS) driver
@ 2026-07-30 16:39 hang.suan.wang
  2026-07-30 16:39 ` [PATCH v3 1/3] firmware: stratix10-svc: increase args array hang.suan.wang
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: hang.suan.wang @ 2026-07-30 16:39 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Dinh Nguyen, linux-kernel,
	Michael S . Tsirkin, Huacai Chen, Florian Fainelli, Chen-Yu Tsai,
	Jonathan Corbet, Shuah Khan, Ethan Nelson-Moore, Herbert Xu,
	Pasha Tatashin, Haren Myneni, Giovanni Cabiddu, Gabriel Whigham,
	Jiri Slaby, linux-doc
  Cc: muhammad.nazim.amirul.nazle.asmade, tze.yee.ng, chee.nouk.phoon,
	genevieve.chan, adrian.ho.yin.ng

From: Hang Suan Wang <hang.suan.wang@altera.com>

This series adds support for the Altera SoCFPGA Crypto Service (FCS), the
runtime cryptographic interface provided by the Secure Device Manager
(SDM). The SDM is the hardware security controller in Altera SoCFPGA
devices. It acts as the root-of-trust device and controls access to
built-in cryptographic hardware such as AES, SHA, a true random number
generator, and Intel PUF. The SDM is responsible for security-critical
functions including secure boot, FPGA bitstream authentication and optional
decryption, remote system update, and runtime crypto services. On the HPS
side, software reaches the SDM through a mailbox interface exposed in Linux
via the stratix10-svc layer, which uses Arm Trusted Firmware SIP SMC calls
underneath.

The FPGA Crypto Service (FCS) is the runtime crypto interface provided by
the SDM. It covers services such as random number generation, AES
operations, HMAC/SHA, key management, attestation, and related security
functions.

This series implements one FCS feature: the Secure Data Object Service
(SDOS), which protects sensitive data at rest. With SDOS the SDM encrypts
and decrypts data using a key derived from a device-unique root key that
never leaves the secure boundary, plus an SDM-generated IV. The host never
handles raw key material or IVs: it supplies plaintext and receives an
authenticated ciphertext object (and vice versa for decryption). A primary
use case is black key provisioning, where operational keys are installed in
protected form without ever being exposed in cleartext.

The driver reaches the SDM through the existing stratix10-svc mailbox using
the Arm Trusted Firmware SIP SMC transport. Data buffers are allocated from
the service-layer memory pool, which provides physically-contiguous memory
whose physical address is handed to the SDM.

The series is organized as follows:
 - Patch 1 (prerequisite) enlarges the stratix10-svc SMC argument array so
   the asynchronous FCS SDOS command can pass its full set of parameters.

 - Patch 2 extends the stratix10-svc service layer with the FCS command
   codes and matching SIP SMC function IDs, adds the Agilex 5
   (intel,agilex5-svc) match, and registers a "stratix10-fcs" platform
   device that an FCS client driver binds to.

 - Patch 3 adds the FCS firmware driver implementing SDOS encrypt/decrypt,
   exposed via an ioctl character device (/dev/socfpga_fcs); the crypto
   session is opened and closed internally and is not part of the user ABI.
   Thus, patches 1 and 2 must be applied first.

Testing:
 - Built for arm64 (defconfig + CONFIG_ALTERA_SOCFPGA_FCS=m).
 - Tested on an Agilex 5 SoC FPGA board (SDOS root key provisioned).
   SDOS encrypt/decrypt round-trip; the decrypted output matches the
   original 32-byte plaintext:

   root@agilex5e:~# hexdump -v -e '/1 "%02x "' secret.bin
   da 21 01 c5 d1 72 85 4b e7 1f 72 8f 60 68 f0 c9
   33 08 9e c1 9d 69 4a 54 61 0a f6 90 58 44 c8 17

   root@agilex5e:~# ./fcs_client -E -i secret.bin -o enc.bin -d 0x1234 -r
                    0xabcd -n 0
   root@agilex5e:~# ./fcs_client -D -i enc.bin -o sdos_decrypt.bin -n 0

   root@agilex5e:~# hexdump -v -e '/1 "%02x "' sdos_decrypt.bin
   da 21 01 c5 d1 72 85 4b e7 1f 72 8f 60 68 f0 c9
   33 08 9e c1 9d 69 4a 54 61 0a f6 90 58 44 c8 17
---
Changes since v2:
socfpga-fcs (front-end):
 - Replace the sysfs store interface with an ioctl character device
   (/dev/socfpga_fcs) using a fixed-width UAPI struct and
   compat_ptr_ioctl(), fixing the KASAN out-of-bounds read and the
   32-bit incompatibility of casting the sysfs buffer as a pointer.
 - Add include/uapi/misc/socfpga-fcs-crypto.h and register the ioctl
   magic in Documentation/userspace-api/ioctl/ioctl-number.rst.
 - Add a .release handler so a session is torn down if the owning fd
   is closed (including on crash).
socfpga-fcs (core):
 - Manage the crypto session internally: SDOS opens and closes its own
   session; reject a concurrent open with -EBUSY. Removes the
   user-visible open/close-session interface and session UUID, fixing
   the session-exhaustion/DoS concern.
 - Harden the async poll loop: keep polling until the deadline and
   always call stratix10_svc_async_done(), fixing the teardown
   use-after-free from the previous -EINPROGRESS early-return and the
   needless full-timeout block.
 - Clear receive_cb only on the synchronous send-error path so a late
   firmware response cannot deref a NULL callback.
 - Set priv = NULL on all fcs_init() error paths so a later probe is
   not permanently rejected with -EBUSY.
 - Read the SDOS owner ID with get_unaligned_le64() for correct
   little-endian handling on big-endian hosts.
stratix10-svc:
 - Enlarge the SMC arguments array so the async SDOS command can
   pass its full parameter set (through a11).
 - In remove(), unregister the child devices before
   stratix10_svc_async_exit() so async_poll() cannot race a freed
   handle.

---
Changes since v1:
stratix10-svc:
 - Forward result registers (kaddr1) for OPEN_SESSION and SDOS_DATA_EXT
   so session ID / output length reach the client.
socfpga-fcs (front-end):
 - Publish sysfs via driver.dev_groups on the platform device instead of
   a raw kobject under /sys/kernel; callbacks now get a struct device.
socfpga-fcs (core):
 - Convert completion timeouts with msecs_to_jiffies(); drop TIMEOUT.
 - On SDM-busy timeout (-EAGAIN), abort without async_done() (no id
   reuse) and return -EINPROGRESS.
 - SDOS: on in-flight abort, leak s_buf/d_buf instead of freeing to
   avoid corruption from late firmware DMA.
 - Validate the caller UUID early in fcs_sdos_crypt().
 - Enforce single instance: -EBUSY in fcs_init() and priv NULL-guard in
   fcs_acquire_cmd_ctx().
 - Drop the always-zero platform attribute and fcs_get_platform().
 - Set/clear receive_cb only around the synchronous send.
 - Use device-lifetime priv->completion for the async path (was on-stack).
 - Use the local ctx snapshot consistently in fcs_sdos_crypt() and
   fcs_session_close().
 - Point sdos.dst_size at priv->sdos_output_size, not a stack variable.
socfpga-fcs.h:
 - Drop platform/AGILEX5_PLAT; add sdos_output_size.
---

Hang Suan Wang (3):
  firmware: stratix10-svc: increase args array
  firmware: stratix10-svc: add FCS crypto-service commands for Agilex 5
  firmware: socfpga-fcs: add Altera SoCFPGA FCS driver with SDOS

 .../userspace-api/ioctl/ioctl-number.rst      |   1 +
 MAINTAINERS                                   |   9 +
 drivers/firmware/Kconfig                      |  17 +
 drivers/firmware/Makefile                     |   2 +
 drivers/firmware/socfpga-fcs-core.c           | 660 ++++++++++++++++++
 drivers/firmware/socfpga-fcs.c                | 227 ++++++
 drivers/firmware/stratix10-svc.c              |  64 +-
 include/linux/firmware/intel/socfpga-fcs.h    | 126 ++++
 include/linux/firmware/intel/stratix10-smc.h  |  64 ++
 .../firmware/intel/stratix10-svc-client.h     |  18 +-
 include/uapi/misc/socfpga-fcs-crypto.h        |  29 +
 11 files changed, 1210 insertions(+), 7 deletions(-)
 create mode 100644 drivers/firmware/socfpga-fcs-core.c
 create mode 100644 drivers/firmware/socfpga-fcs.c
 create mode 100644 include/linux/firmware/intel/socfpga-fcs.h
 create mode 100644 include/uapi/misc/socfpga-fcs-crypto.h

-- 
2.43.7


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v3 1/3] firmware: stratix10-svc: increase args array
  2026-07-30 16:39 [PATCH v3 0/3] Add Altera SoCFPGA Crypto Service (FCS) driver hang.suan.wang
@ 2026-07-30 16:39 ` hang.suan.wang
  2026-07-30 16:39 ` [PATCH v3 2/3] firmware: stratix10-svc: add FCS crypto-service commands for Agilex 5 hang.suan.wang
  2026-07-30 16:39 ` [PATCH v3 3/3] firmware: socfpga-fcs: add Altera SoCFPGA FCS driver with SDOS hang.suan.wang
  2 siblings, 0 replies; 4+ messages in thread
From: hang.suan.wang @ 2026-07-30 16:39 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Dinh Nguyen, linux-kernel,
	Michael S . Tsirkin, Huacai Chen, Florian Fainelli, Chen-Yu Tsai,
	Jonathan Corbet, Shuah Khan, Ethan Nelson-Moore, Herbert Xu,
	Pasha Tatashin, Haren Myneni, Giovanni Cabiddu, Gabriel Whigham,
	Jiri Slaby, linux-doc
  Cc: muhammad.nazim.amirul.nazle.asmade, tze.yee.ng, chee.nouk.phoon,
	genevieve.chan, adrian.ho.yin.ng

From: Hang Suan Wang <hang.suan.wang@altera.com>

Increase args array from 3 to 6, for the SDOS encryption to call smc
call which is used for args to be passed via registers and not
physically mapped buffer.

Signed-off-by: Hang Suan Wang <hang.suan.wang@altera.com>
---
 drivers/firmware/stratix10-svc.c                    | 6 ++++--
 include/linux/firmware/intel/stratix10-svc-client.h | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index 5e20057ee344..d389be1c6690 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c
@@ -169,7 +169,7 @@ struct stratix10_svc_data {
 	size_t size_output;
 	u32 command;
 	u32 flag;
-	u64 arg[3];
+	u64 arg[6];
 };
 
 /**
@@ -1797,7 +1797,9 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
 	p_data->arg[0] = p_msg->arg[0];
 	p_data->arg[1] = p_msg->arg[1];
 	p_data->arg[2] = p_msg->arg[2];
-	p_data->size = p_msg->payload_length;
+	p_data->arg[3] = p_msg->arg[3];
+	p_data->arg[4] = p_msg->arg[4];
+	p_data->arg[5] = p_msg->arg[5];
 	p_data->chan = chan;
 	pr_debug("%s: %s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n",
 		 __func__,
diff --git a/include/linux/firmware/intel/stratix10-svc-client.h b/include/linux/firmware/intel/stratix10-svc-client.h
index 3edd93502bf8..190d89d602e9 100644
--- a/include/linux/firmware/intel/stratix10-svc-client.h
+++ b/include/linux/firmware/intel/stratix10-svc-client.h
@@ -210,7 +210,7 @@ struct stratix10_svc_client_msg {
 	void *payload_output;
 	size_t payload_length_output;
 	enum stratix10_svc_command_code command;
-	u64 arg[3];
+	u64 arg[6];
 };
 
 /**
-- 
2.43.7


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v3 2/3] firmware: stratix10-svc: add FCS crypto-service commands for Agilex 5
  2026-07-30 16:39 [PATCH v3 0/3] Add Altera SoCFPGA Crypto Service (FCS) driver hang.suan.wang
  2026-07-30 16:39 ` [PATCH v3 1/3] firmware: stratix10-svc: increase args array hang.suan.wang
@ 2026-07-30 16:39 ` hang.suan.wang
  2026-07-30 16:39 ` [PATCH v3 3/3] firmware: socfpga-fcs: add Altera SoCFPGA FCS driver with SDOS hang.suan.wang
  2 siblings, 0 replies; 4+ messages in thread
From: hang.suan.wang @ 2026-07-30 16:39 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Dinh Nguyen, linux-kernel,
	Michael S . Tsirkin, Huacai Chen, Florian Fainelli, Chen-Yu Tsai,
	Jonathan Corbet, Shuah Khan, Ethan Nelson-Moore, Herbert Xu,
	Pasha Tatashin, Haren Myneni, Giovanni Cabiddu, Gabriel Whigham,
	Jiri Slaby, linux-doc
  Cc: muhammad.nazim.amirul.nazle.asmade, tze.yee.ng, chee.nouk.phoon,
	genevieve.chan, adrian.ho.yin.ng

From: Hang Suan Wang <hang.suan.wang@altera.com>

The Agilex 5 Secure Device Manager (SDM 1.5) exposes an FPGA Crypto
Service (FCS) over the existing SIP SMC mailbox: a session-based
interface for crypto primitives such as SDOS (Secure Data Object
Service) encrypt/decrypt. The service layer has no command to drive it
yet.

Configure stratix10-svc about this interface so an in-kernel FCS client
can use it:

  - add the client command codes COMMAND_FCS_CRYPTO_OPEN_SESSION,
    COMMAND_FCS_CRYPTO_CLOSE_SESSION and COMMAND_FCS_SDOS_DATA_EXT (all
    asynchronous)

  - add the matching asynchronous SIP SMC function IDs
    (INTEL_SIP_SMC_ASYNC_FCS_OPEN_CS_SESSION,
    INTEL_SIP_SMC_ASYNC_FCS_CLOSE_CS_SESSION and
    INTEL_SIP_SMC_ASYNC_FCS_CRYPTION_EXT) with their register-usage
    documentation;

  - match "intel,agilex5-svc" and register a "stratix10-fcs" child
    platform device, mirroring the existing RSU child, so an FCS client
    driver can bind without a dedicated device-tree node;

  - dispatch the new commands in the asynchronous send and response
    paths; for the SDOS data command, translate the source and
    destination buffers (allocated from the service-layer gen_pool) to
    physical addresses and pass them, together with the session/context
    IDs and owner ID, to the SDM.

The transport is unchanged: Agilex 5 reuses the SIP SMC calling
convention and async mailbox ABI the driver already implements, so no
new transport mechanism is required.

The SDOS SMMU-remapped address slots currently carry the buffer
physical addresses; SMMU remapping support is added in a follow-up
series.

This is a prerequisite for the SoCFPGA FCS driver, the first in-tree
consumer of these commands.

Signed-off-by: Hang Suan Wang <hang.suan.wang@altera.com>
Reviewed-by: Dinh Nguyen <dinguyen@kernel.org>
---
 drivers/firmware/stratix10-svc.c              | 58 +++++++++++++++--
 include/linux/firmware/intel/stratix10-smc.h  | 64 +++++++++++++++++++
 .../firmware/intel/stratix10-svc-client.h     | 16 +++++
 3 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index d389be1c6690..73ffaed4c8c1 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c
@@ -45,6 +45,7 @@
 
 /* stratix10 service layer clients */
 #define STRATIX10_RSU				"stratix10-rsu"
+#define STRATIX10_FCS				"stratix10-fcs"
 
 /* Maximum number of SDM client IDs. */
 #define MAX_SDM_CLIENT_IDS			16
@@ -104,9 +105,11 @@ struct stratix10_svc_chan;
 /**
  * struct stratix10_svc - svc private data
  * @stratix10_svc_rsu: pointer to stratix10 RSU device
+ * @stratix10_svc_fcs: pointer to stratix10 FCS device
  */
 struct stratix10_svc {
 	struct platform_device *stratix10_svc_rsu;
+	struct platform_device *stratix10_svc_fcs;
 };
 
 /**
@@ -1319,6 +1322,30 @@ int stratix10_svc_async_send(struct stratix10_svc_chan *chan, void *msg,
 		STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(handle->transaction_id);
 
 	switch (p_msg->command) {
+	case COMMAND_FCS_CRYPTO_OPEN_SESSION:
+		args.a0 = INTEL_SIP_SMC_ASYNC_FCS_OPEN_CS_SESSION;
+		break;
+	case COMMAND_FCS_CRYPTO_CLOSE_SESSION:
+		args.a0 = INTEL_SIP_SMC_ASYNC_FCS_CLOSE_CS_SESSION;
+		args.a2 = p_msg->arg[0];
+		break;
+	case COMMAND_FCS_SDOS_DATA_EXT:
+		args.a0 = INTEL_SIP_SMC_ASYNC_FCS_CRYPTION_EXT;
+		args.a2 = p_msg->arg[0];
+		args.a3 = p_msg->arg[1];
+		args.a4 = p_msg->arg[2];
+		/* payloads are allocated from the svc gen_pool; pass phys addr */
+		args.a5 = gen_pool_virt_to_phys(ctrl->genpool,
+						(unsigned long)p_msg->payload);
+		args.a6 = p_msg->payload_length;
+		args.a7 = gen_pool_virt_to_phys(ctrl->genpool,
+						(unsigned long)p_msg->payload_output);
+		args.a8 = p_msg->payload_length_output;
+		args.a9 = p_msg->arg[3];
+		/* SMMU remapping is added later; pass phys addr for now */
+		args.a10 = args.a5;
+		args.a11 = args.a7;
+		break;
 	case COMMAND_RSU_GET_SPT_TABLE:
 		args.a0 = INTEL_SIP_SMC_ASYNC_RSU_GET_SPT;
 		break;
@@ -1408,8 +1435,13 @@ static int stratix10_svc_async_prepare_response(struct stratix10_svc_chan *chan,
 	data->status = STRATIX10_GET_SDM_STATUS_CODE(handle->res.a1);
 
 	switch (p_msg->command) {
+	case COMMAND_FCS_CRYPTO_CLOSE_SESSION:
 	case COMMAND_RSU_NOTIFY:
 		break;
+	case COMMAND_FCS_CRYPTO_OPEN_SESSION:
+	case COMMAND_FCS_SDOS_DATA_EXT:
+		data->kaddr1 = (void *)&handle->res.a2;
+		break;
 	case COMMAND_RSU_GET_SPT_TABLE:
 		data->kaddr1 = (void *)&handle->res.a2;
 		data->kaddr2 = (void *)&handle->res.a3;
@@ -1913,6 +1945,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
 static const struct of_device_id stratix10_svc_drv_match[] = {
 	{.compatible = "intel,stratix10-svc"},
 	{.compatible = "intel,agilex-svc"},
+	{.compatible = "intel,agilex5-svc"},
 	{},
 };
 
@@ -2016,20 +2049,36 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
 
 	ret = platform_device_add(svc->stratix10_svc_rsu);
 	if (ret)
-		goto err_put_device;
+		goto err_put_rsu;
+
+	svc->stratix10_svc_fcs = platform_device_alloc(STRATIX10_FCS, 0);
+	if (!svc->stratix10_svc_fcs) {
+		dev_err(dev, "failed to allocate %s device\n", STRATIX10_FCS);
+		ret = -ENOMEM;
+		goto err_unregister_rsu;
+	}
+
+	ret = platform_device_add(svc->stratix10_svc_fcs);
+	if (ret)
+		goto err_put_fcs;
 
 	ret = of_platform_default_populate(dev_of_node(dev), NULL, dev);
 	if (ret)
-		goto err_unregister_rsu_dev;
+		goto err_unregister_fcs;
 
 	pr_info("Intel Service Layer Driver Initialized\n");
 
 	return 0;
 
-err_unregister_rsu_dev:
+err_unregister_fcs:
+	platform_device_unregister(svc->stratix10_svc_fcs);
+	goto err_unregister_rsu;
+err_put_fcs:
+	platform_device_put(svc->stratix10_svc_fcs);
+err_unregister_rsu:
 	platform_device_unregister(svc->stratix10_svc_rsu);
 	goto err_free_fifos;
-err_put_device:
+err_put_rsu:
 	platform_device_put(svc->stratix10_svc_rsu);
 err_free_fifos:
 	/* only remove from list if list_add_tail() was reached */
@@ -2052,6 +2101,7 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
 	struct stratix10_svc *svc = ctrl->svc;
 
 	platform_device_unregister(svc->stratix10_svc_rsu);
+	platform_device_unregister(svc->stratix10_svc_fcs);
 
 	stratix10_svc_async_exit(ctrl);
 
diff --git a/include/linux/firmware/intel/stratix10-smc.h b/include/linux/firmware/intel/stratix10-smc.h
index 9224974fffc4..8e989b279bb3 100644
--- a/include/linux/firmware/intel/stratix10-smc.h
+++ b/include/linux/firmware/intel/stratix10-smc.h
@@ -646,6 +646,70 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
 #define INTEL_SIP_SMC_FCS_GET_PROVISION_DATA \
 	INTEL_SIP_SMC_STD_CALL_VAL(INTEL_SIP_SMC_FUNCID_FCS_GET_PROVISION_DATA)
 
+/**
+ * Request INTEL_SIP_SMC_ASYNC_FCS_CRYPTION_EXT
+ * Async call to perform encryption/decryption
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_ASYNC_FCS_CRYPTION_EXT
+ * a1 transaction job id
+ * a2 session ID
+ * a3 context ID
+ * a4 cryption operating mode (1 for encryption and 0 for decryption)
+ * a5 physical address of source
+ * a6 size of source
+ * a7 physical address of destination
+ * a8 size of destination
+ * a9 sdos ownership
+ * a10 smmu remapped address of source
+ * a11 smmu remapped address of destination
+ * a12-a17 not used
+ *
+ * Return status:
+ * a0 INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_STATUS_ERROR
+ * a1-a17 not used
+ */
+#define INTEL_SIP_SMC_ASYNC_FUNC_ID_FCS_CRYPTION_EXT (0x12F)
+#define INTEL_SIP_SMC_ASYNC_FCS_CRYPTION_EXT \
+	INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_FCS_CRYPTION_EXT)
+
+/**
+ * Request INTEL_SIP_SMC_ASYNC_FCS_OPEN_CS_SESSION
+ * Async call to open and establish a crypto service session with firmware
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_FCS_OPEN_CRYPTO_SERVICE_SESSION
+ * a1 transaction job id
+ * a2-a17 not used
+ *
+ * Return status:
+ * a0 INTEL_SIP_SMC_STATUS_OK ,INTEL_SIP_SMC_STATUS_REJECTED
+ * or INTEL_SIP_SMC_STATUS_BUSY
+ * a1-a17 not used
+ */
+#define INTEL_SIP_SMC_ASYNC_FUNC_ID_FCS_OPEN_CS_SESSION (0x13A)
+#define INTEL_SIP_SMC_ASYNC_FCS_OPEN_CS_SESSION \
+	INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_FCS_OPEN_CS_SESSION)
+
+/**
+ * Request INTEL_SIP_SMC_ASYNC_FCS_CLOSE_CS_SESSION
+ * Async call to close a service session
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_ASYNC_FCS_CLOSE_CS_SESSION
+ * a1 transaction job id
+ * a2 session ID
+ * a3-a17 not used
+ *
+ * Return status:
+ * a0 INTEL_SIP_SMC_STATUS_OK ,INTEL_SIP_SMC_STATUS_REJECTED
+ * or INTEL_SIP_SMC_STATUS_BUSY
+ * a1-a17 not used
+ */
+#define INTEL_SIP_SMC_ASYNC_FUNC_ID_FCS_CLOSE_CS_SESSION (0x13B)
+#define INTEL_SIP_SMC_ASYNC_FCS_CLOSE_CS_SESSION \
+	INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_FCS_CLOSE_CS_SESSION)
+
 /**
  * Request INTEL_SIP_SMC_HWMON_READTEMP
  * Sync call to request temperature
diff --git a/include/linux/firmware/intel/stratix10-svc-client.h b/include/linux/firmware/intel/stratix10-svc-client.h
index 190d89d602e9..2bb751f3b212 100644
--- a/include/linux/firmware/intel/stratix10-svc-client.h
+++ b/include/linux/firmware/intel/stratix10-svc-client.h
@@ -7,6 +7,8 @@
 #ifndef __STRATIX10_SVC_CLIENT_H
 #define __STRATIX10_SVC_CLIENT_H
 
+#include <linux/types.h>
+
 /*
  * Service layer driver supports client names
  *
@@ -122,6 +124,15 @@ struct stratix10_svc_chan;
  * @COMMAND_SMC_SVC_VERSION: Non-mailbox SMC SVC API Version,
  * return status is SVC_STATUS_OK
  *
+ * @COMMAND_FCS_CRYPTO_OPEN_SESSION: open the crypto service session(s),
+ * return status is SVC_STATUS_OK or SVC_STATUS_ERROR
+ *
+ * @COMMAND_FCS_CRYPTO_CLOSE_SESSION: close the crypto service session(s),
+ * return status is SVC_STATUS_OK or SVC_STATUS_ERROR
+ *
+ * @COMMAND_FCS_SDOS_DATA_EXT: extend SDOS data encryption & decryption,
+ * return status is SVC_STATUS_OK or SVC_STATUS_ERROR
+ *
  * @COMMAND_MBOX_SEND_CMD: send generic mailbox command, return status is
  * SVC_STATUS_OK or SVC_STATUS_ERROR
  *
@@ -185,6 +196,11 @@ enum stratix10_svc_command_code {
 	COMMAND_FCS_RANDOM_NUMBER_GEN,
 	/* for general status poll */
 	COMMAND_POLL_SERVICE_STATUS = 40,
+	/* for crypto service */
+	COMMAND_FCS_CRYPTO_OPEN_SESSION = 50,
+	COMMAND_FCS_CRYPTO_CLOSE_SESSION,
+	/* for extended SDOS encrypt/decrypt */
+	COMMAND_FCS_SDOS_DATA_EXT = 82,
 	/* for generic mailbox send command */
 	COMMAND_MBOX_SEND_CMD = 100,
 	/* Non-mailbox SMC Call */
-- 
2.43.7


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v3 3/3] firmware: socfpga-fcs: add Altera SoCFPGA FCS driver with SDOS
  2026-07-30 16:39 [PATCH v3 0/3] Add Altera SoCFPGA Crypto Service (FCS) driver hang.suan.wang
  2026-07-30 16:39 ` [PATCH v3 1/3] firmware: stratix10-svc: increase args array hang.suan.wang
  2026-07-30 16:39 ` [PATCH v3 2/3] firmware: stratix10-svc: add FCS crypto-service commands for Agilex 5 hang.suan.wang
@ 2026-07-30 16:39 ` hang.suan.wang
  2 siblings, 0 replies; 4+ messages in thread
From: hang.suan.wang @ 2026-07-30 16:39 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Dinh Nguyen, linux-kernel,
	Michael S . Tsirkin, Huacai Chen, Florian Fainelli, Chen-Yu Tsai,
	Jonathan Corbet, Shuah Khan, Ethan Nelson-Moore, Herbert Xu,
	Pasha Tatashin, Haren Myneni, Giovanni Cabiddu, Gabriel Whigham,
	Jiri Slaby, linux-doc
  Cc: muhammad.nazim.amirul.nazle.asmade, tze.yee.ng, chee.nouk.phoon,
	genevieve.chan, adrian.ho.yin.ng

From: Hang Suan Wang <hang.suan.wang@altera.com>

Add the Altera SoCFPGA Crypto Service (FCS) driver, which exposes the
Secure Data Object Service (SDOS) encrypt/decrypt operation to
non-secure host software.

The SDOS is the FCS feature that protects data at rest: the SDM encrypts
and decrypts using a key derived from a device-unique SDOS root key plus an
SDM-generated IV, so the host never handles raw key material or IVs. It
only submits plaintext it already owns and receives authenticated
ciphertext objects managed by the SDM. A primary use case is black key
provisioning, where operational keys are installed without ever appearing
in cleartext.

The driver is a standalone module and describes no hardware of its own.
It binds by name to the "stratix10-fcs" platform device that the
stratix10-svc driver registers in code, so no device-tree node is needed,
and detects the SoC by matching the service-layer compatible. It exposes
the following sysfs attributes. The SDOS requests are issued to the SDM
through the stratix10-svc asynchronous SIP SMC. Source and destination
buffers are taken from the service-layer memory pool so the SDM can reach
them via physical or SMMU-remapped addresses.

For encryption the SDM returns a structured object (metadata, IV, HMAC,
ciphertext); for decryption it validates the HMAC, recovers the parameters
from the object header, and enforces a 64-bit owner ID so that only the
creator of an object can decrypt it.

The SDOS driver will open crypto session in SDM and close the session
after use. During the usage, the session will be lock.

Signed-off-by: Hang Suan Wang <hang.suan.wang@altera.com>
---
 .../userspace-api/ioctl/ioctl-number.rst      |   1 +
 MAINTAINERS                                   |   9 +
 drivers/firmware/Kconfig                      |  17 +
 drivers/firmware/Makefile                     |   2 +
 drivers/firmware/socfpga-fcs-core.c           | 660 ++++++++++++++++++
 drivers/firmware/socfpga-fcs.c                | 227 ++++++
 include/linux/firmware/intel/socfpga-fcs.h    | 126 ++++
 include/uapi/misc/socfpga-fcs-crypto.h        |  29 +
 8 files changed, 1071 insertions(+)
 create mode 100644 drivers/firmware/socfpga-fcs-core.c
 create mode 100644 drivers/firmware/socfpga-fcs.c
 create mode 100644 include/linux/firmware/intel/socfpga-fcs.h
 create mode 100644 include/uapi/misc/socfpga-fcs-crypto.h

diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 3f0ef1e27eb0..645d54ce1009 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -346,6 +346,7 @@ Code  Seq#    Include File                                             Comments
                                                                        <mailto:luzmaximilian@gmail.com>
 0xA5  20-2F  linux/surface_aggregator/dtx.h                            Microsoft Surface DTX driver
                                                                        <mailto:luzmaximilian@gmail.com>
+0xA6  00-1F  uapi/misc/socfpga-fcs-crypto.h                            Altera SoCFPGA FCS (Crypto Service)
 0xAA  00-3F  linux/uapi/linux/userfaultfd.h
 0xAB  00-1F  linux/nbd.h
 0xAC  00-1F  linux/raw.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 62d53465ef9b..357d02f467dc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -946,6 +946,15 @@ ALPS PS/2 TOUCHPAD DRIVER
 R:	Pali Rohár <pali@kernel.org>
 F:	drivers/input/mouse/alps.*
 
+ALTERA FCS DRIVER
+M:	Hang Suan Wang <hang.suan.wang@altera.com>
+M:	Genevieve Chan <genevieve.chan@altera.com>
+L:	linux-arm-kernel@lists.infradead.org
+S:	Maintained
+F:	drivers/firmware/socfpga-fcs*
+F:	include/linux/firmware/intel/socfpga-fcs*
+F:	include/uapi/misc/socfpga-fcs*
+
 ALTERA MAILBOX DRIVER
 M:	Tien Sung Ang <tiensung.ang@altera.com>
 S:	Maintained
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 12dc70254842..5337e367fca1 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -172,6 +172,23 @@ config INTEL_STRATIX10_RSU
 
 	  Say Y here if you want Intel RSU support.
 
+config ALTERA_SOCFPGA_FCS
+	tristate "Altera SoCFPGA Crypto Services (FCS)"
+	depends on INTEL_STRATIX10_SERVICE
+	help
+	  Altera SoCFPGA Crypto Services (FCS) driver gives user space
+	  access to the crypto services of the Secure Device Manager (SDM)
+	  through the Intel Service Layer, with requests forwarded to Arm
+	  Trusted Firmware.
+
+	  The SDM executes or authorizes the requests using device-rooted
+	  security resources. Protected key material stays within the
+	  secure firmware boundary and is never exposed to non-secure host
+	  software.
+
+	  Say Y here to add support for Altera SoCFPGA Crypto Services
+	  (FCS).
+
 config MTK_ADSP_IPC
 	tristate "MTK ADSP IPC Protocol driver"
 	depends on MTK_ADSP_MBOX
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 4ddec2820c96..e9f52f0e5f7a 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_EDD)		+= edd.o
 obj-$(CONFIG_DMIID)		+= dmi-id.o
 obj-$(CONFIG_INTEL_STRATIX10_SERVICE) += stratix10-svc.o
 obj-$(CONFIG_INTEL_STRATIX10_RSU)     += stratix10-rsu.o
+obj-$(CONFIG_ALTERA_SOCFPGA_FCS) += altera-fcs.o
+altera-fcs-y := socfpga-fcs.o socfpga-fcs-core.o
 obj-$(CONFIG_ISCSI_IBFT_FIND)	+= iscsi_ibft_find.o
 obj-$(CONFIG_ISCSI_IBFT)	+= iscsi_ibft.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)	+= memmap.o
diff --git a/drivers/firmware/socfpga-fcs-core.c b/drivers/firmware/socfpga-fcs-core.c
new file mode 100644
index 000000000000..36192e89b0cf
--- /dev/null
+++ b/drivers/firmware/socfpga-fcs-core.c
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Altera Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/unaligned.h>
+#include <linux/firmware/intel/socfpga-fcs.h>
+#include <linux/firmware/intel/stratix10-svc-client.h>
+
+#define OWNER_ID_OFFSET				12
+
+#define SDOS_DECRYPTION_REPROVISION_KEY_WARN	0x102
+#define SDOS_DECRYPTION_NOT_LATEST_KEY_WARN	0x103
+
+#define MSG_RETRY				3
+#define FCS_RETRY_SLEEP_MS			1
+
+static struct socfpga_fcs_priv *priv;
+
+/**
+ * fcs_atf_version_callback() - service-layer callback for the ATF version query
+ * @client: pointer to the stratix10-svc client
+ * @data: pointer to the service-layer callback data
+ *
+ * Store the returned Arm Trusted Firmware version (or mailbox error) in @priv
+ * and signal completion to the waiting caller.
+ */
+static void fcs_atf_version_callback(struct stratix10_svc_client *client,
+				     struct stratix10_svc_cb_data *data)
+{
+	struct socfpga_fcs_priv *p = client->priv;
+
+	p->status = data->status;
+	if (data->status == BIT(SVC_STATUS_OK)) {
+		p->status = 0;
+		p->atf_version[0] = *((unsigned int *)data->kaddr1);
+		p->atf_version[1] = *((unsigned int *)data->kaddr2);
+		p->atf_version[2] = *((unsigned int *)data->kaddr3);
+	} else if (data->status == BIT(SVC_STATUS_ERROR)) {
+		p->status = *((unsigned int *)data->kaddr1);
+		dev_err(client->dev, "mbox_error=0x%x\n", p->status);
+	}
+
+	complete(&p->completion);
+}
+
+/**
+ * fcs_async_callback() - completion callback for an async service request
+ * @ptr: pointer to the completion to signal
+ */
+static void fcs_async_callback(void *ptr)
+{
+	if (ptr)
+		complete(ptr);
+}
+
+/**
+ * fcs_svc_send_request() - build and send an FCS command to the service layer
+ * @command: FCS command code to dispatch
+ * @timeout: time to wait for completion, in milliseconds
+ *
+ * Build the service-layer message for @command and send it through the
+ * stratix10-svc service driver, using the synchronous path for the ATF version
+ * query and the asynchronous mailbox path (with retries) for the remaining
+ * commands.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int fcs_svc_send_request(enum fcs_command_code command,
+				unsigned long timeout)
+{
+	struct fcs_cmd_context *k_ctx = &priv->k_ctx;
+	struct stratix10_svc_cb_data data;
+	void *handle = NULL;
+	int status, index;
+	int ret = 0;
+	struct stratix10_svc_client_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+	unsigned long deadline = jiffies + msecs_to_jiffies(timeout);
+
+	priv->status = 0;
+	priv->resp = 0;
+
+	switch (command) {
+	case FCS_DEV_CRYPTO_OPEN_SESSION:
+		pr_debug("Sending command: COMMAND_FCS_CRYPTO_OPEN_SESSION\n");
+		msg->command = COMMAND_FCS_CRYPTO_OPEN_SESSION;
+		break;
+
+	case FCS_DEV_CRYPTO_CLOSE_SESSION:
+		pr_debug("Sending command: COMMAND_FCS_CRYPTO_CLOSE_SESSION with session_id: 0x%x\n",
+			 priv->session_id);
+		msg->arg[0] = priv->session_id;
+		msg->command = COMMAND_FCS_CRYPTO_CLOSE_SESSION;
+		break;
+
+	case FCS_DEV_ATF_VERSION:
+		pr_debug("Sending command: COMMAND_SMC_ATF_BUILD_VER\n");
+		msg->command = COMMAND_SMC_ATF_BUILD_VER;
+		break;
+
+	case FCS_DEV_SDOS_DATA_EXT:
+		pr_debug("Sending command: COMMAND_FCS_SDOS_DATA_EXT with session_id: 0x%x, context_id: 0x%x, op_mode: 0x%x, own: 0x%llx\n",
+			 priv->session_id, k_ctx->sdos.context_id,
+			 k_ctx->sdos.op_mode, k_ctx->sdos.own);
+		msg->arg[0] = priv->session_id;
+		msg->arg[1] = k_ctx->sdos.context_id;
+		msg->arg[2] = k_ctx->sdos.op_mode;
+		msg->arg[3] = k_ctx->sdos.own;
+		msg->payload = k_ctx->sdos.src;
+		msg->payload_length = k_ctx->sdos.src_size;
+		msg->payload_output = k_ctx->sdos.dst;
+		msg->payload_length_output = *k_ctx->sdos.dst_size;
+		msg->command = COMMAND_FCS_SDOS_DATA_EXT;
+		break;
+
+	default:
+		pr_err("Unknown command: 0x%x\n", command);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret) {
+		kfree(msg);
+		return ret;
+	}
+
+	if (command == FCS_DEV_ATF_VERSION) {
+		reinit_completion(&priv->completion);
+
+		/*
+		 * receive_cb is a persistent field on the shared client and
+		 * is only consumed by the synchronous stratix10_svc_send()
+		 * path. Set it immediately before the send and clear it right
+		 * after so it is non-NULL only for the duration of this
+		 * transaction. This keeps the callback correct per command and
+		 * prevents a future synchronous caller from silently
+		 * inheriting a stale fcs_atf_version_callback.
+		 */
+		priv->client.receive_cb = fcs_atf_version_callback;
+
+		ret = stratix10_svc_send(priv->chan, msg);
+		if (ret) {
+			pr_err("failed to send message to service channel\n");
+			priv->client.receive_cb = NULL;
+			goto fun_ret;
+		}
+
+		if (!wait_for_completion_timeout(&priv->completion,
+						 msecs_to_jiffies(timeout))) {
+			pr_err("svc timeout to get completed status\n");
+			ret = -ETIMEDOUT;
+		}
+fun_ret:
+		kfree(msg);
+		return ret;
+	}
+
+	/*
+	 * Use the device-lifetime priv->completion as the async callback arg
+	 * rather than an on-stack completion: on a timeout/abort this function
+	 * returns while the svc layer still holds a pointer to it in the
+	 * transaction handle, so a stack object would be freed under it. FCS
+	 * serializes commands under priv->lock (one in-flight), so reusing
+	 * priv->completion here is safe.
+	 */
+	reinit_completion(&priv->completion);
+
+	for (index = 0; index < MSG_RETRY; index++) {
+		status = stratix10_svc_async_send(priv->chan, msg, &handle,
+						  fcs_async_callback,
+						  &priv->completion);
+		if (status == 0)
+			break;
+		msleep(FCS_RETRY_SLEEP_MS);
+	}
+
+	if (!handle || status != 0) {
+		pr_err("Failed to send async message\n");
+		kfree(msg);
+		return status;
+	}
+
+	ret = -ETIMEDOUT;
+	while (!time_after(jiffies, deadline)) {
+		status = stratix10_svc_async_poll(priv->chan, handle, &data);
+
+		if (status == 0) {
+			ret = 0;
+			break;
+		}
+
+		/*
+		 * -EAGAIN means the SDM is still processing. Other transient
+		 * poll errors can also surface on the first polls, before the
+		 * SDM has produced its initial response. Since the async send
+		 * already succeeded, keep polling until the deadline instead of
+		 * bailing out on the first non-zero status: abandoning an
+		 * in-flight transaction here would orphan the SDM-side session
+		 * (the SDM allows only one crypto session at a time), causing
+		 * later commands to be rejected. Record the last status so the
+		 * caller sees the real error if the deadline is reached.
+		 */
+		ret = status;
+		msleep(FCS_RETRY_SLEEP_MS);
+	}
+
+	if (ret) {
+		pr_err("Failed to poll async message\n");
+		goto out;
+	}
+
+	priv->status = data.status;
+
+	/*
+	 * A non-zero SDM mailbox status is a firmware-level result, not a
+	 * transport failure. Record it in priv->status and return transport
+	 * success so the caller can relay the exact code to user space
+	 * (error_code) and choose how to fail; do not overload -EFAULT here.
+	 */
+	if (data.status) {
+		pr_err("%s: SDM mailbox status 0x%x\n", __func__, data.status);
+		priv->resp = 0;
+		goto out;
+	}
+
+	if (data.kaddr1)
+		priv->resp = *((u32 *)data.kaddr1);
+	else
+		priv->resp = 0;
+
+out:
+	stratix10_svc_async_done(priv->chan, handle);
+	kfree(msg);
+
+	return ret;
+}
+
+/**
+ * fcs_open_session_locked() - open a crypto session on the SDM
+ *
+ * Enforce the single-session rule and, on success, record the SDM session
+ * handle in @priv->session_id and generate the associated session UUID. The
+ * caller must hold @priv->lock (taken by fcs_acquire_cmd_ctx()). This helper
+ * never touches user space; @priv->status carries the mailbox status.
+ *
+ * Return: 0 on success, -EBUSY if a session is already open, or negative
+ *         errno on transport/mailbox failure.
+ */
+static int fcs_open_session_locked(void)
+{
+	int ret;
+
+	if (priv->session_id)
+		/* SDM allows one crypto session at a time */
+		return -EBUSY;
+
+	ret = fcs_svc_send_request(FCS_DEV_CRYPTO_OPEN_SESSION,
+				   SVC_FCS_REQUEST_TIMEOUT_MS);
+	if (ret)
+		return ret;
+
+	if (priv->status)
+		return -EIO;
+
+	uuid_gen(&priv->uuid_id);
+	priv->session_id = priv->resp;
+
+	return 0;
+}
+
+/**
+ * fcs_close_session_locked() - close the crypto session on the SDM
+ *
+ * Close the currently open session, if any. The caller must hold
+ * @priv->lock. The local session handle is dropped unconditionally so that a
+ * failed or stuck close cannot permanently occupy the single-session slot and
+ * lock out future opens. @priv->status carries the mailbox status.
+ *
+ * Return: 0 on success or when no session is open, negative errno otherwise.
+ */
+static int fcs_close_session_locked(void)
+{
+	int ret;
+
+	if (!priv->session_id)
+		/* nothing to close */
+		return 0;
+
+	ret = fcs_svc_send_request(FCS_DEV_CRYPTO_CLOSE_SESSION,
+				   SVC_FCS_REQUEST_TIMEOUT_MS);
+
+	priv->session_id = 0;
+	priv->session_owner = NULL;
+	memset(&priv->uuid_id, 0, sizeof(priv->uuid_id));
+
+	if (!ret && priv->status)
+		ret = -EIO;
+
+	return ret;
+}
+
+/**
+ * fcs_session_set_owner() - record the open file that owns the session
+ * @file: open file that opened the session (identity only)
+ *
+ * The caller must hold @priv->lock (taken by fcs_acquire_cmd_ctx()).
+ */
+void fcs_session_set_owner(const struct file *file)
+{
+	if (priv)
+		priv->session_owner = file;
+}
+
+/**
+ * fcs_session_release() - close a session left open by a departing file
+ * @file: open file being released
+ *
+ * Close the crypto session if @file is the one that opened it. Used by the
+ * misc-device .release path so a session opened via the explicit ioctl is
+ * torn down when its owning fd is closed, including on process crash/exit.
+ */
+void fcs_session_release(const struct file *file)
+{
+	if (!priv)
+		return;
+
+	mutex_lock(&priv->lock);
+	if (priv->session_owner == file)
+		fcs_close_session_locked();
+	mutex_unlock(&priv->lock);
+}
+
+/**
+ * fcs_get_atf_version() - return the cached Arm Trusted Firmware version
+ * @version: array of three u32 entries to receive the major, minor and patch
+ *           version numbers
+ */
+void fcs_get_atf_version(u32 *version)
+{
+	memcpy(version, priv->atf_version, sizeof(priv->atf_version));
+}
+
+/**
+ * fcs_sdos_crypt() - perform an SDOS encrypt or decrypt operation
+ * @k_ctx: pointer to the kernel-side FCS command context
+ *
+ * Allocate service-layer source and destination buffers, copy the input from
+ * user space, drive the SDOS data command and copy the result and length back
+ * to user space. The operation direction is selected by @k_ctx->sdos.op_mode.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int fcs_sdos_crypt(struct fcs_cmd_context *const k_ctx)
+{
+	void *s_buf = NULL, *d_buf = NULL;
+	struct fcs_cmd_context ctx;
+	u32 output_size;
+	u32 dst_cap;
+	int ret = 0;
+
+	memcpy(&ctx, k_ctx, sizeof(struct fcs_cmd_context));
+
+	if (!ctx.sdos.dst || !ctx.sdos.dst_size)
+		return -EINVAL;
+
+	/* Caller-provided output buffer capacity (in/out parameter) */
+	if (copy_from_user(&dst_cap, ctx.sdos.dst_size, sizeof(dst_cap)))
+		return -EFAULT;
+
+	if (ctx.sdos.op_mode) {
+		output_size = SDOS_ENCRYPTED_MAX_SZ;
+		/* encrypt: input is header + plaintext */
+		if (ctx.sdos.src_size < SDOS_DECRYPTED_MIN_SZ ||
+		    ctx.sdos.src_size > SDOS_DECRYPTED_MAX_SZ) {
+			pr_err("Invalid SDOS src_size %u\n", ctx.sdos.src_size);
+			return -EINVAL;
+		}
+	} else {
+		output_size = SDOS_DECRYPTED_MAX_SZ;
+		/* decrypt: input is header + plaintext + HMAC */
+		if (ctx.sdos.src_size < SDOS_ENCRYPTED_MIN_SZ ||
+		    ctx.sdos.src_size > SDOS_ENCRYPTED_MAX_SZ) {
+			pr_err("Invalid SDOS src_size %u\n", ctx.sdos.src_size);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * SDOS is a single-shot operation: open a dedicated crypto session,
+	 * run the command and close the session before returning. The
+	 * single-session guard makes this fail with -EBUSY if a session (for
+	 * example a multi-step sequence) is already active.
+	 */
+	ret = fcs_open_session_locked();
+	if (ret) {
+		pr_err("SDOS: failed to open session ret: %d\n", ret);
+		return ret;
+	}
+
+	s_buf = stratix10_svc_allocate_memory(priv->chan, ctx.sdos.src_size);
+	if (IS_ERR(s_buf)) {
+		ret = -ENOMEM;
+		pr_err("Failed to allocate memory for SDOS input data kernel buffer ret: %d\n",
+		       ret);
+		goto close_session;
+	}
+
+	/*
+	 * The remaining k_ctx writes intentionally target priv->k_ctx (k_ctx
+	 * points at it): fcs_svc_send_request() reads the outgoing request from
+	 * priv->k_ctx, so the kernel buffers and params are staged there rather
+	 * than in the local ctx snapshot. dst_size must point at device-lifetime
+	 * storage (priv->sdos_output_size), never a caller stack variable, so
+	 * the staged pointer cannot dangle after this function returns.
+	 */
+	priv->sdos_output_size = output_size;
+	k_ctx->sdos.dst_size = &priv->sdos_output_size;
+
+	d_buf = stratix10_svc_allocate_memory(priv->chan, output_size);
+	if (IS_ERR(d_buf)) {
+		ret = -ENOMEM;
+		pr_err("Failed to allocate memory for SDOS output kernel buffer ret: %d\n", ret);
+		goto free_sbuf;
+	}
+
+	/* Copy the user space input data to the input data kernel buffer */
+	ret = copy_from_user(s_buf, ctx.sdos.src,
+			     ctx.sdos.src_size) ? -EFAULT : 0;
+	if (ret) {
+		pr_err("Failed to copy SDOS data from user to kernel buffer ret: %d\n", ret);
+		goto free_dbuf;
+	}
+
+	/* Owner ID is stored little-endian in the SDOS header (offset 12) */
+	k_ctx->sdos.own = get_unaligned_le64((u8 *)s_buf + OWNER_ID_OFFSET);
+	k_ctx->sdos.src = s_buf;
+	k_ctx->sdos.dst = d_buf;
+
+	ret = fcs_svc_send_request(FCS_DEV_SDOS_DATA_EXT,
+				   SVC_FCS_REQUEST_TIMEOUT_MS);
+
+	if (ret) {
+		/*
+		 * Transport failure or timeout. The service layer has already
+		 * completed the transaction (async_done); free the buffers and
+		 * close the session on the way out.
+		 */
+		pr_err("Failed to send the cmd=%d,ret=%d\n", FCS_DEV_SDOS_DATA_EXT, ret);
+		goto free_dbuf;
+	}
+	if (priv->status &&
+	    priv->status != SDOS_DECRYPTION_REPROVISION_KEY_WARN &&
+	    priv->status != SDOS_DECRYPTION_NOT_LATEST_KEY_WARN) {
+		ret = -EIO;
+		pr_err("Failed to perform SDOS operation ret: %d Mailbox Status = 0x%x\n",
+		       ret, priv->status);
+		goto copy_mbox_status;
+	}
+
+	/*
+	 * priv->resp is reported by firmware; never trust it to read back
+	 * more than the kernel output buffer (d_buf) actually holds,
+	 * otherwise the copy below would leak adjacent kernel memory.
+	 */
+	if (priv->resp > output_size) {
+		pr_err("SDOS output %u exceeds kernel buffer %u\n",
+		       priv->resp, output_size);
+		ret = -EIO;
+		goto copy_mbox_status;
+	}
+
+	/* Do not write past the caller-provided output buffer */
+	if (priv->resp > dst_cap) {
+		pr_err("SDOS output %u exceeds caller buffer %u\n",
+		       priv->resp, dst_cap);
+		ret = -EMSGSIZE;
+		goto copy_mbox_status;
+	}
+
+	/* Copy the encrypted/decrypted output from kernel space to user space */
+	ret = copy_to_user(ctx.sdos.dst, d_buf, priv->resp) ? -EFAULT : 0;
+	if (ret) {
+		pr_err("Failed to copy encrypted output to user ret: %d\n", ret);
+		goto copy_mbox_status;
+	}
+
+	/* Copy the encrypted output length from kernel space to user space */
+	ret = copy_to_user(ctx.sdos.dst_size, &priv->resp,
+			   sizeof(priv->resp)) ? -EFAULT : 0;
+	if (ret)
+		pr_err("Failed to copy encrypted output length to user ret: %d\n", ret);
+
+copy_mbox_status:
+	if (copy_to_user(ctx.error_code_addr, &priv->status,
+			 sizeof(priv->status))) {
+		pr_err("Failed to copy mailbox status code to user\n");
+		/* surface the copy failure only if nothing failed earlier */
+		if (!ret)
+			ret = -EFAULT;
+	}
+free_dbuf:
+	stratix10_svc_free_memory(priv->chan, d_buf);
+free_sbuf:
+	stratix10_svc_free_memory(priv->chan, s_buf);
+close_session:
+	/* Best-effort close; local session state is dropped regardless. */
+	fcs_close_session_locked();
+
+	return ret;
+}
+
+/**
+ * fcs_acquire_cmd_ctx() - take the FCS lock and return the command context
+ *
+ * Serialises access to the shared command context across concurrent callers.
+ * The caller must release it with fcs_release_cmd_ctx().
+ *
+ * Return: pointer to the locked FCS command context, or NULL if the driver is
+ *         not initialised.
+ */
+struct fcs_cmd_context *fcs_acquire_cmd_ctx(void)
+{
+	if (!priv)
+		return NULL;
+
+	mutex_lock(&priv->lock);
+	return &priv->k_ctx;
+}
+
+/**
+ * fcs_release_cmd_ctx() - release the FCS command context lock
+ * @k_ctx: pointer to the FCS command context previously acquired
+ */
+void fcs_release_cmd_ctx(struct fcs_cmd_context *const k_ctx)
+{
+	mutex_unlock(&priv->lock);
+}
+
+/**
+ * fcs_read_version_from_atf() - query the Arm Trusted Firmware build version
+ *
+ * Send the ATF version command to the SDM and cache the result in @priv.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int fcs_read_version_from_atf(void)
+{
+	int ret = 0;
+
+	ret = fcs_svc_send_request(FCS_DEV_ATF_VERSION,
+				   SVC_FCS_REQUEST_TIMEOUT_MS);
+	if (ret) {
+		pr_err("Failed to send the cmd=%d,ret=%d\n", FCS_DEV_ATF_VERSION, ret);
+		return ret;
+	}
+
+	if (priv->status) {
+		ret = -EIO;
+		pr_err("Mailbox error, Failed to read ATF version ret: %d\n", ret);
+	}
+
+	stratix10_svc_done(priv->chan);
+
+	return ret;
+}
+
+/**
+ * fcs_init() - allocate and initialise the FCS private state
+ * @dev: pointer to fcs device
+ *
+ * Allocate @priv, request the service channel, register the async client,
+ * and read the ATF version.
+ *
+ * Return: 0 on success, -EPROBE_DEFER or negative errno on failure.
+ */
+int fcs_init(struct device *dev)
+{
+	int ret;
+
+	if (priv)
+		/* singleton: one FCS instance only */
+		return -EBUSY;
+
+	priv = devm_kzalloc(dev, sizeof(struct socfpga_fcs_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+
+	priv->dev = dev;
+	priv->client.dev = dev;
+	priv->client.receive_cb = NULL;
+	priv->client.priv = priv;
+
+	priv->chan = stratix10_svc_request_channel_byname(&priv->client,
+							  SVC_CLIENT_FCS);
+	if (IS_ERR(priv->chan)) {
+		pr_err("couldn't get service channel %s\n", SVC_CLIENT_FCS);
+		ret = -EPROBE_DEFER;
+		goto err_clear;
+	}
+
+	ret = stratix10_svc_add_async_client(priv->chan, true);
+	if (ret) {
+		pr_err("Failed to add async client\n");
+		goto free_chan;
+	}
+
+	init_completion(&priv->completion);
+
+	fcs_read_version_from_atf();
+
+	return 0;
+
+free_chan:
+	stratix10_svc_free_channel(priv->chan);
+err_clear:
+	/* drop dangling devm pointer */
+	priv = NULL;
+
+	return ret;
+}
+
+/**
+ * fcs_deinit() - tear down the FCS private state
+ *
+ * Close any open session, remove the async client, free the service channel
+ * and clear @priv.
+ */
+void fcs_deinit(void)
+{
+	if (priv && priv->session_id) {
+		int ret = fcs_close_session_locked();
+
+		if (ret)
+			pr_err("Failed to close FCS service session,ret=%d\n", ret);
+	}
+
+	if (priv) {
+		stratix10_svc_remove_async_client(priv->chan);
+		stratix10_svc_free_channel(priv->chan);
+	}
+
+	priv = NULL;
+}
+
+/**
+ * fcs_cleanup() - release the FCS service channel and clear the state
+ */
+void fcs_cleanup(void)
+{
+	if (priv)
+		stratix10_svc_free_channel(priv->chan);
+
+	priv = NULL;
+}
diff --git a/drivers/firmware/socfpga-fcs.c b/drivers/firmware/socfpga-fcs.c
new file mode 100644
index 000000000000..d2d09032319a
--- /dev/null
+++ b/drivers/firmware/socfpga-fcs.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, Altera Corporation
+ */
+
+#include <linux/firmware/intel/socfpga-fcs.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/uaccess.h>
+#include <linux/util_macros.h>
+#include <uapi/misc/socfpga-fcs-crypto.h>
+
+/**
+ * atf_version_show() - report the Arm Trusted Firmware build version
+ * @dev: pointer to fcs device
+ * @attr: device attribute
+ * @buf: pointer to character buffer to receive the version string
+ *
+ * Return: number of bytes written to @buf.
+ */
+static ssize_t atf_version_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int version[3];
+
+	fcs_get_atf_version(version);
+	return sysfs_emit(buf, "%u.%u.%u\n", version[0], version[1], version[2]);
+}
+
+/**
+ * fcs_sdos() - perform an SDOS encrypt/decrypt operation
+ * @k_ctx: locked FCS command context to populate
+ * @uarg: user pointer to a struct fcs_ioc_sdos
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static long fcs_sdos(struct fcs_cmd_context *k_ctx, void __user *uarg)
+{
+	struct fcs_ioc_sdos u;
+
+	if (copy_from_user(&u, uarg, sizeof(u)))
+		return -EFAULT;
+
+	if (u.__pad)
+		return -EINVAL;
+
+	memset(k_ctx, 0, sizeof(*k_ctx));
+	k_ctx->error_code_addr = u64_to_user_ptr(u.error_code);
+	k_ctx->sdos.context_id = u.context_id;
+	k_ctx->sdos.op_mode    = u.op_mode;
+	k_ctx->sdos.src        = u64_to_user_ptr(u.src);
+	k_ctx->sdos.src_size   = u.src_size;
+	k_ctx->sdos.dst        = u64_to_user_ptr(u.dst);
+	k_ctx->sdos.dst_size   = u64_to_user_ptr(u.dst_size);
+
+	return fcs_sdos_crypt(k_ctx);
+}
+
+/**
+ * fcs_ioctl() - dispatch an FCS ioctl command
+ * @file: open file for the FCS misc device
+ * @cmd: ioctl command code
+ * @arg: user pointer to the command-specific argument structure
+ *
+ * Take the shared command context under the FCS lock, dispatch @cmd to its
+ * handler and release the context before returning.
+ *
+ * Return: 0 on success, -ENODEV if the driver is not initialised, -ENOTTY for
+ *         an unknown command, or a negative errno from the handler.
+ */
+static long fcs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	void __user *uarg = (void __user *)arg;
+	struct fcs_cmd_context *k_ctx;
+	long ret;
+
+	k_ctx = fcs_acquire_cmd_ctx();
+	if (!k_ctx)
+		/* driver not initialised */
+		return -ENODEV;
+
+	switch (cmd) {
+	case FCS_IOC_SDOS:
+		ret = fcs_sdos(k_ctx, uarg);
+		break;
+	default:
+		ret = -ENOTTY;
+		break;
+	}
+
+	fcs_release_cmd_ctx(k_ctx);
+	return ret;
+}
+
+/**
+ * fcs_release() - close a session left open by a departing client
+ * @inode: inode of the misc device
+ * @file: open file being released
+ *
+ * Guarantees the crypto session is torn down when its owning fd is closed,
+ * including on process crash/exit, so a client that opens a session (for a
+ * multi-step sequence) and dies before closing it cannot leave the SDM's
+ * single session slot permanently occupied.
+ *
+ * Return: 0 always.
+ */
+static int fcs_release(struct inode *inode, struct file *file)
+{
+	fcs_session_release(file);
+	return 0;
+}
+
+static const struct file_operations fcs_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= fcs_ioctl,
+	.compat_ioctl	= compat_ptr_ioctl,
+	.release	= fcs_release,
+};
+
+static struct miscdevice fcs_miscdev = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "socfpga_fcs",
+	.fops	= &fcs_fops,
+};
+
+static DEVICE_ATTR_RO(atf_version);
+
+static struct attribute *fcs_attrs[] = {
+	&dev_attr_atf_version.attr,
+	NULL
+};
+
+static const struct attribute_group fcs_group = {
+	.attrs = fcs_attrs,
+};
+
+static const struct attribute_group *fcs_groups[] = {
+	&fcs_group,
+	NULL,
+};
+
+/**
+ * fcs_driver_probe() - probe the FCS platform device
+ * @pdev: pointer to the FCS platform device
+ *
+ * Initialise the FCS state and register the misc device that exposes the
+ * ioctl command interface. The sysfs attribute groups are published
+ * automatically by the driver core via fcs_driver.driver.dev_groups.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int fcs_driver_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	ret = fcs_init(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize FCS\n");
+
+	ret = misc_register(&fcs_miscdev);
+	if (ret) {
+		fcs_deinit();
+		return dev_err_probe(dev, ret, "Failed to register misc device\n");
+	}
+
+	return 0;
+}
+
+/**
+ * fcs_driver_remove() - remove the FCS platform device
+ * @pdev: pointer to the FCS platform device
+ *
+ * Tear down the FCS state. The sysfs attribute groups are removed
+ * automatically by the driver core.
+ */
+static void fcs_driver_remove(struct platform_device *pdev)
+{
+	misc_deregister(&fcs_miscdev);
+	fcs_deinit();
+}
+
+static struct platform_driver fcs_driver = {
+	.probe = fcs_driver_probe,
+	.remove = fcs_driver_remove,
+	.driver = {
+		.name = "stratix10-fcs",
+		.dev_groups = fcs_groups,
+	},
+};
+
+/**
+ * socfpga_fcs_init() - register the FCS platform driver
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int __init socfpga_fcs_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&fcs_driver);
+	if (ret)
+		pr_err("Failed to register platform driver: %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * socfpga_fcs_exit() - unregister the FCS platform driver
+ */
+static void __exit socfpga_fcs_exit(void)
+{
+	platform_driver_unregister(&fcs_driver);
+}
+
+module_init(socfpga_fcs_init);
+module_exit(socfpga_fcs_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Altera SoCFPGA FCS SDOS encrypt/decrypt driver");
+MODULE_AUTHOR("Altera Corporation");
+MODULE_ALIAS("platform:stratix10-fcs");
diff --git a/include/linux/firmware/intel/socfpga-fcs.h b/include/linux/firmware/intel/socfpga-fcs.h
new file mode 100644
index 000000000000..f32b010d209d
--- /dev/null
+++ b/include/linux/firmware/intel/socfpga-fcs.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 Altera Corporation
+ *
+ * SDOS-only subset of the SoCFPGA FCS (FPGA Crypto Service) interface,
+ * shared between the driver front-end (socfpga-fcs.c) and the command
+ * engine (socfpga-fcs-core.c).
+ */
+#ifndef __SOCFPGA_FCS_H
+#define __SOCFPGA_FCS_H
+
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/uuid.h>
+#include <linux/firmware/intel/stratix10-svc-client.h>
+
+struct file;
+
+#define SDOS_HEADER_SZ		40
+#define SDOS_HMAC_SZ		48
+#define SDOS_PLAINDATA_MIN_SZ	32
+#define SDOS_PLAINDATA_MAX_SZ	32672
+#define SDOS_DECRYPTED_MIN_SZ	(SDOS_PLAINDATA_MIN_SZ + SDOS_HEADER_SZ)
+#define SDOS_DECRYPTED_MAX_SZ	(SDOS_PLAINDATA_MAX_SZ + SDOS_HEADER_SZ)
+#define SDOS_ENCRYPTED_MIN_SZ	(SDOS_PLAINDATA_MIN_SZ + SDOS_HEADER_SZ + SDOS_HMAC_SZ)
+#define SDOS_ENCRYPTED_MAX_SZ	(SDOS_PLAINDATA_MAX_SZ + SDOS_HEADER_SZ + SDOS_HMAC_SZ)
+
+#pragma pack(push, 1)
+struct fcs_cmd_context {
+	/* Error status variable address */
+	int *error_code_addr;
+	/*
+	 * A union is used so future multi-step crypto operations can add their
+	 * own per-command parameter blocks alongside SDOS.
+	 */
+	union {
+		struct {
+			u32 context_id;
+			u32 op_mode;
+			char *src;
+			u32 src_size;
+			char *dst;
+			u32 *dst_size;
+			u64 own;
+		} sdos;
+	};
+};
+
+#pragma pack(pop)
+
+/**
+ * Private driver state for the SoCFPGA FCS that holds the SDM/ATF service
+ * channel, the shared command context and the lock that guards it, and the
+ * latest mailbox status/response.
+ */
+struct socfpga_fcs_priv {
+	/* Communication channel */
+	struct stratix10_svc_chan *chan;
+	struct fcs_cmd_context k_ctx;
+	struct stratix10_svc_client client;
+	struct completion completion;
+	/*
+	 * Serializes FCS command submission: guards the shared k_ctx and the
+	 * single in-flight mailbox transaction (completion/status/resp) so only
+	 * one SDM request is outstanding at a time. This is the lock taken by
+	 * fcs_acquire_cmd_ctx() and dropped by fcs_release_cmd_ctx().
+	 */
+	struct mutex lock;
+	int status;
+	u32 resp;
+	u32 session_id;
+	uuid_t uuid_id;
+	/* fd that holds the session */
+	const struct file *session_owner;
+	struct device *dev;
+	u32 atf_version[3];
+	/*
+	 * Backing store for the SDOS output-buffer capacity. The outgoing
+	 * request stages k_ctx.sdos.dst_size to point here (device-lifetime)
+	 * instead of at a caller stack variable, so the pointer never dangles.
+	 */
+	u32 sdos_output_size;
+};
+
+enum fcs_command_code {
+	FCS_DEV_COMMAND_NONE = 0,
+	FCS_DEV_CRYPTO_OPEN_SESSION,
+	FCS_DEV_CRYPTO_CLOSE_SESSION,
+	FCS_DEV_SDOS_DATA_EXT,
+	FCS_DEV_ATF_VERSION,
+};
+
+/* Take the FCS lock and return the shared command context. */
+struct fcs_cmd_context *fcs_acquire_cmd_ctx(void);
+
+/* Release the FCS lock previously taken by fcs_acquire_cmd_ctx(). */
+void fcs_release_cmd_ctx(struct fcs_cmd_context *const k_ctx);
+
+/* Allocate the FCS state and set up the service channel; read ATF version. */
+int fcs_init(struct device *dev);
+
+/* Close any open session and release the service channel. */
+void fcs_deinit(void);
+
+/* Release the service channel and clear the FCS state. */
+void fcs_cleanup(void);
+
+/*
+ * Record the open file that owns the current session (caller holds lock).
+ * Reserved for multi-step crypto sequences whose session must live across
+ * several ioctls; SDOS opens and closes its session within a single call.
+ */
+void fcs_session_set_owner(const struct file *file);
+
+/* Close the session if @file owns it; used by the .release path. */
+void fcs_session_release(const struct file *file);
+
+/* Return the cached Arm Trusted Firmware build version. */
+void fcs_get_atf_version(u32 *version);
+
+/* Perform an SDOS (Secure Data Object Service) encrypt/decrypt operation. */
+int fcs_sdos_crypt(struct fcs_cmd_context *const k_ctx);
+
+#endif /* SOCFPGA_FCS_H */
diff --git a/include/uapi/misc/socfpga-fcs-crypto.h b/include/uapi/misc/socfpga-fcs-crypto.h
new file mode 100644
index 000000000000..bf31a90901f1
--- /dev/null
+++ b/include/uapi/misc/socfpga-fcs-crypto.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * Description:
+ * This driver is developed for the SDM SoCFPGA Crypto Service (FCS). It
+ * provides an ioctl interface for the SDOS (Secure Data Object Service)
+ * encrypt/decrypt operation. The crypto session is opened and closed by the
+ * kernel internally, so it is not part of the user ABI.
+ */
+#ifndef __SOCFPGA_FCS_CRYPTO_H
+#define __SOCFPGA_FCS_CRYPTO_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+struct fcs_ioc_sdos {
+	__u64 error_code;	/* __user ptr to __s32 (out)              */
+	__u64 src;		/* __user ptr to input buffer (in)        */
+	__u64 dst;		/* __user ptr to output buffer (out)      */
+	__u64 dst_size;		/* __user ptr to __u32 capacity/len (in/out) */
+	__u32 context_id;	/* (in)  */
+	__u32 op_mode;		/* (in)  */
+	__u32 src_size;		/* (in)  */
+	__u32 __pad;		/* must be 0 */
+};
+
+#define FCS_IOC_MAGIC		0xA6
+#define FCS_IOC_SDOS		_IOWR(FCS_IOC_MAGIC, 1, struct fcs_ioc_sdos)
+
+#endif /* __SOCFPGA_FCS_CRYPTO_H */
-- 
2.43.7


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-07-30 16:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 16:39 [PATCH v3 0/3] Add Altera SoCFPGA Crypto Service (FCS) driver hang.suan.wang
2026-07-30 16:39 ` [PATCH v3 1/3] firmware: stratix10-svc: increase args array hang.suan.wang
2026-07-30 16:39 ` [PATCH v3 2/3] firmware: stratix10-svc: add FCS crypto-service commands for Agilex 5 hang.suan.wang
2026-07-30 16:39 ` [PATCH v3 3/3] firmware: socfpga-fcs: add Altera SoCFPGA FCS driver with SDOS hang.suan.wang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.