* [PATCH v2 1/2] firmware: qcom: scm: Add SCM storage interface support
2026-01-26 11:44 [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Junhao Xie
@ 2026-01-26 11:44 ` Junhao Xie
2026-01-28 13:39 ` Konrad Dybcio
2026-01-26 11:44 ` [PATCH v2 2/2] mtd: devices: Add Qualcomm SCM storage driver Junhao Xie
` (3 subsequent siblings)
4 siblings, 1 reply; 20+ messages in thread
From: Junhao Xie @ 2026-01-26 11:44 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu, Junhao Xie
Add infrastructure to support accessing TrustZone-protected storage
devices through SCM (Secure Channel Manager) calls. Some Qualcomm
platforms protect their firmware storage (typically SPI NOR flash)
via TrustZone, making it inaccessible from the non-secure world.
Signed-off-by: Junhao Xie <bigfoot@radxa.com>
Tested-by: Xilin Wu <sophon@radxa.com>
---
drivers/firmware/qcom/qcom_scm.c | 161 +++++++++++++++++++++++++++++++++
drivers/firmware/qcom/qcom_scm.h | 3 +
include/linux/firmware/qcom/qcom_scm.h | 34 +++++++
3 files changed, 198 insertions(+)
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 1a6f85e46..f6e643cb1 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -66,6 +66,27 @@ struct qcom_scm_mem_map_info {
__le64 mem_size;
};
+struct qcom_scm_storage_cmd {
+ __le64 storage_type;
+ __le64 slot_num;
+ __le64 lun;
+ __le64 guid_ptr;
+ __le64 storage_cmd;
+} __packed;
+
+struct qcom_scm_storage_cmd_details {
+ __le64 lba;
+ __le64 length;
+ __le64 data_ptr;
+ __le64 data_size;
+} __packed;
+
+struct qcom_scm_storage_payload {
+ struct qcom_scm_storage_cmd cmd;
+ struct qcom_scm_storage_cmd_details details;
+ u8 data[];
+};
+
/**
* struct qcom_scm_qseecom_resp - QSEECOM SCM call response.
* @result: Result or status of the SCM call. See &enum qcom_scm_qseecom_result.
@@ -111,6 +132,17 @@ enum qcom_scm_qseecom_tz_cmd_info {
QSEECOM_TZ_CMD_INFO_VERSION = 3,
};
+#define STORAGE_RESULT_SUCCESS 0
+#define STORAGE_RESULT_NO_MEMORY 1
+#define STORAGE_RESULT_INVALID_PARAMETER 2
+#define STORAGE_RESULT_STORAGE_ERROR 3
+#define STORAGE_RESULT_ACCESS_DENIED 4
+#define STORAGE_RESULT_NOT_SUPPORTED 5
+#define STORAGE_RESULT_MAC_MISMATCH 6
+#define STORAGE_RESULT_ALREADY_RUNNING 7
+#define STORAGE_RESULT_PARTITION_NOT_FOUND 8
+#define STORAGE_RESULT_READONLY 9
+
#define QSEECOM_MAX_APP_NAME_SIZE 64
#define SHMBRIDGE_RESULT_NOTSUPP 4
@@ -2198,6 +2230,132 @@ static void qcom_scm_qtee_init(struct qcom_scm *scm)
devm_add_action_or_reset(scm->dev, qcom_scm_qtee_free, qtee_dev);
}
+int qcom_scm_storage_send_cmd(enum qcom_scm_storage_type storage_type,
+ enum qcom_scm_storage_cmd_id cmd_id,
+ u64 lba, void *data, size_t size)
+{
+ struct qcom_scm_storage_payload *payload __free(qcom_tzmem) = NULL;
+ struct qcom_scm_res scm_res = {};
+ struct qcom_scm_desc desc = {};
+ phys_addr_t payload_addr;
+ size_t buf_size;
+ int ret;
+
+ buf_size = sizeof(*payload);
+ if (data)
+ buf_size += size;
+
+ payload = qcom_tzmem_alloc(__scm->mempool, buf_size, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ memset(payload, 0, buf_size);
+ if (data)
+ memcpy(payload->data, data, size);
+
+ payload->cmd.storage_type = cpu_to_le64(storage_type);
+ payload->cmd.storage_cmd = cpu_to_le64(cmd_id);
+
+ payload->details.lba = cpu_to_le64(lba);
+ if (payload) {
+ payload_addr = qcom_tzmem_to_phys(payload->data);
+ payload->details.data_ptr = cpu_to_le64(payload_addr);
+ }
+ payload->details.length = cpu_to_le64(size);
+
+ desc.svc = QCOM_SCM_SVC_STORAGE;
+ desc.cmd = QCOM_SCM_STORAGE_CMD;
+ desc.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, QCOM_SCM_VAL,
+ QCOM_SCM_RW, QCOM_SCM_VAL);
+ desc.args[0] = qcom_tzmem_to_phys(&payload->cmd);
+ desc.args[1] = sizeof(payload->cmd);
+ desc.args[2] = qcom_tzmem_to_phys(&payload->details);
+ desc.args[3] = sizeof(payload->details);
+ desc.owner = ARM_SMCCC_OWNER_SIP;
+
+ ret = qcom_scm_call(__scm->dev, &desc, &scm_res);
+ if (ret)
+ return ret;
+
+ if (data)
+ memcpy(data, payload->data, size);
+
+ switch (scm_res.result[0]) {
+ case STORAGE_RESULT_SUCCESS:
+ return 0;
+ case STORAGE_RESULT_NO_MEMORY:
+ return -ENOMEM;
+ case STORAGE_RESULT_INVALID_PARAMETER:
+ return -EINVAL;
+ case STORAGE_RESULT_STORAGE_ERROR:
+ return -EIO;
+ case STORAGE_RESULT_ACCESS_DENIED:
+ return -EACCES;
+ case STORAGE_RESULT_NOT_SUPPORTED:
+ return -EOPNOTSUPP;
+ case STORAGE_RESULT_MAC_MISMATCH:
+ return -EBADMSG;
+ case STORAGE_RESULT_ALREADY_RUNNING:
+ return -EALREADY;
+ case STORAGE_RESULT_PARTITION_NOT_FOUND:
+ return -ENOENT;
+ case STORAGE_RESULT_READONLY:
+ return -EROFS;
+ default:
+ return -EIO;
+ }
+}
+EXPORT_SYMBOL_GPL(qcom_scm_storage_send_cmd);
+
+static void qcom_scm_storage_free(void *data)
+{
+ struct platform_device *storage_dev = data;
+
+ platform_device_unregister(storage_dev);
+}
+
+static void qcom_scm_storage_init(struct qcom_scm *scm)
+{
+ struct qcom_scm_storage_info info;
+ struct platform_device *storage_dev;
+ u64 total_blocks;
+ u32 block_size;
+ int ret;
+
+ if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_STORAGE,
+ QCOM_SCM_STORAGE_CMD))
+ return;
+
+ ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
+ QCOM_SCM_STORAGE_GET_INFO,
+ 0, &info, sizeof(info));
+ if (ret < 0) {
+ dev_warn(scm->dev, "scm storage get info failed: %d\n", ret);
+ return;
+ }
+
+ total_blocks = le64_to_cpu(info.total_blocks);
+ block_size = le32_to_cpu(info.block_size);
+
+ dev_dbg(scm->dev, "scm storage size %llu bytes\n",
+ total_blocks * block_size);
+
+ storage_dev = platform_device_alloc("qcom_scm_storage", -1);
+ if (!storage_dev)
+ return;
+
+ storage_dev->dev.parent = scm->dev;
+
+ ret = platform_device_add(storage_dev);
+ if (ret) {
+ platform_device_put(storage_dev);
+ return;
+ }
+
+ devm_add_action_or_reset(scm->dev, qcom_scm_storage_free,
+ storage_dev);
+}
+
/**
* qcom_scm_is_available() - Checks if SCM is available
*/
@@ -2433,6 +2591,9 @@ static int qcom_scm_probe(struct platform_device *pdev)
/* Initialize the QTEE object interface. */
qcom_scm_qtee_init(scm);
+ /* Initialize the SCM storage interface. */
+ qcom_scm_storage_init(scm);
+
return 0;
}
diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h
index a56c8212c..3b68b33c5 100644
--- a/drivers/firmware/qcom/qcom_scm.h
+++ b/drivers/firmware/qcom/qcom_scm.h
@@ -149,6 +149,9 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev);
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
+#define QCOM_SCM_SVC_STORAGE 0x1a
+#define QCOM_SCM_STORAGE_CMD 0x01
+
#define QCOM_SCM_SVC_WAITQ 0x24
#define QCOM_SCM_WAITQ_RESUME 0x02
#define QCOM_SCM_WAITQ_GET_WQ_CTX 0x03
diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h
index a55ca7712..644c3cf46 100644
--- a/include/linux/firmware/qcom/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
@@ -53,6 +53,36 @@ enum qcom_scm_ice_cipher {
QCOM_SCM_ICE_CIPHER_AES_256_CBC = 4,
};
+enum qcom_scm_storage_type {
+ QCOM_SCM_STORAGE_NULL = 0,
+ QCOM_SCM_STORAGE_SPINOR = 1,
+};
+
+enum qcom_scm_storage_cmd_id {
+ QCOM_SCM_STORAGE_INIT = 0,
+ QCOM_SCM_STORAGE_READ = 1,
+ QCOM_SCM_STORAGE_WRITE = 2,
+ QCOM_SCM_STORAGE_ERASE = 3,
+ QCOM_SCM_STORAGE_GET_INFO = 4,
+ QCOM_SCM_STORAGE_DEINIT = 5,
+};
+
+#define QCOM_SCM_STORAGE_FW_VER_LEN 32
+#define QCOM_SCM_STORAGE_MEM_TYPE_LEN 5
+#define QCOM_SCM_STORAGE_PROD_NAME_LEN 32
+
+struct qcom_scm_storage_info {
+ __le64 total_blocks;
+ __le32 block_size;
+ __le32 page_size;
+ __le32 num_physical;
+ __le64 manufacturer_id;
+ __le64 serial_num;
+ char fw_version[QCOM_SCM_STORAGE_FW_VER_LEN];
+ char memory_type[QCOM_SCM_STORAGE_MEM_TYPE_LEN];
+ char product_name[QCOM_SCM_STORAGE_PROD_NAME_LEN];
+} __packed;
+
#define QCOM_SCM_PERM_READ 0x4
#define QCOM_SCM_PERM_WRITE 0x2
#define QCOM_SCM_PERM_EXEC 0x1
@@ -181,4 +211,8 @@ int qcom_scm_qtee_invoke_smc(phys_addr_t inbuf, size_t inbuf_size,
int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size,
u64 *result, u64 *response_type);
+int qcom_scm_storage_send_cmd(enum qcom_scm_storage_type storage_type,
+ enum qcom_scm_storage_cmd_id cmd_id,
+ u64 lba, void *payload, size_t size);
+
#endif
--
2.52.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH v2 1/2] firmware: qcom: scm: Add SCM storage interface support
2026-01-26 11:44 ` [PATCH v2 1/2] firmware: qcom: scm: Add SCM storage interface support Junhao Xie
@ 2026-01-28 13:39 ` Konrad Dybcio
2026-01-30 10:58 ` Junhao Xie
0 siblings, 1 reply; 20+ messages in thread
From: Konrad Dybcio @ 2026-01-28 13:39 UTC (permalink / raw)
To: Junhao Xie, Bjorn Andersson, Konrad Dybcio, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu
On 1/26/26 12:44 PM, Junhao Xie wrote:
> Add infrastructure to support accessing TrustZone-protected storage
> devices through SCM (Secure Channel Manager) calls. Some Qualcomm
> platforms protect their firmware storage (typically SPI NOR flash)
> via TrustZone, making it inaccessible from the non-secure world.
>
> Signed-off-by: Junhao Xie <bigfoot@radxa.com>
> Tested-by: Xilin Wu <sophon@radxa.com>
> ---
[...]
> +int qcom_scm_storage_send_cmd(enum qcom_scm_storage_type storage_type,
> + enum qcom_scm_storage_cmd_id cmd_id,
> + u64 lba, void *data, size_t size)
Please add kerneldoc, as this is an exported function
> +{
> + struct qcom_scm_storage_payload *payload __free(qcom_tzmem) = NULL;
> + struct qcom_scm_res scm_res = {};
> + struct qcom_scm_desc desc = {};
> + phys_addr_t payload_addr;
> + size_t buf_size;
> + int ret;
> +
> + buf_size = sizeof(*payload);
> + if (data)
> + buf_size += size;
> +
> + payload = qcom_tzmem_alloc(__scm->mempool, buf_size, GFP_KERNEL);
> + if (!payload)
> + return -ENOMEM;
> +
> + memset(payload, 0, buf_size);
You're overwriting the data part a line below, let's just zero out the
cmd+details (sizeof(*payload)) part
> + if (data)
(please add a \n above - normally
foo = xyz;
if (abc)
...
implies the condition takes into account the previous line)
[...]
> + if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_STORAGE,
> + QCOM_SCM_STORAGE_CMD))
> + return;
> +
> + ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
> + QCOM_SCM_STORAGE_GET_INFO,
> + 0, &info, sizeof(info));
I'm curious what happens if the call is available but SPINOR is not
populated onboard..
I thiiiink it should return STORAGE_RESULT_INVALID_PARAMETER but I'm not
a 100% sure. Guess we'll see down the road.
> + if (ret < 0) {
> + dev_warn(scm->dev, "scm storage get info failed: %d\n", ret);
> + return;
> + }
> +
> + total_blocks = le64_to_cpu(info.total_blocks);
> + block_size = le32_to_cpu(info.block_size);
> +
> + dev_dbg(scm->dev, "scm storage size %llu bytes\n",
> + total_blocks * block_size);
> +
> + storage_dev = platform_device_alloc("qcom_scm_storage", -1);
-1 is PLATFORM_DEVID_NONE
Let's use PLATFORM_DEVID_AUTO to allow potentially multiple instances of
this driver being spawned down the road
Konrad
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH v2 1/2] firmware: qcom: scm: Add SCM storage interface support
2026-01-28 13:39 ` Konrad Dybcio
@ 2026-01-30 10:58 ` Junhao Xie
0 siblings, 0 replies; 20+ messages in thread
From: Junhao Xie @ 2026-01-30 10:58 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Konrad Dybcio, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu, Junhao Xie
On 2026/1/28 21:39, Konrad Dybcio wrote:
> On 1/26/26 12:44 PM, Junhao Xie wrote:
>> Add infrastructure to support accessing TrustZone-protected storage
>> devices through SCM (Secure Channel Manager) calls. Some Qualcomm
>> platforms protect their firmware storage (typically SPI NOR flash)
>> via TrustZone, making it inaccessible from the non-secure world.
>>
>> Signed-off-by: Junhao Xie <bigfoot@radxa.com>
>> Tested-by: Xilin Wu <sophon@radxa.com>
>> ---
> [...]
>
>> +int qcom_scm_storage_send_cmd(enum qcom_scm_storage_type storage_type,
>> + enum qcom_scm_storage_cmd_id cmd_id,
>> + u64 lba, void *data, size_t size)
> Please add kerneldoc, as this is an exported function
I will add kerneldoc for qcom_scm_storage_send_cmd in v3
>> +{
>> + struct qcom_scm_storage_payload *payload __free(qcom_tzmem) = NULL;
>> + struct qcom_scm_res scm_res = {};
>> + struct qcom_scm_desc desc = {};
>> + phys_addr_t payload_addr;
>> + size_t buf_size;
>> + int ret;
>> +
>> + buf_size = sizeof(*payload);
>> + if (data)
>> + buf_size += size;
>> +
>> + payload = qcom_tzmem_alloc(__scm->mempool, buf_size, GFP_KERNEL);
>> + if (!payload)
>> + return -ENOMEM;
>> +
>> + memset(payload, 0, buf_size);
> You're overwriting the data part a line below, let's just zero out the
> cmd+details (sizeof(*payload)) part
>
>> + if (data)
> (please add a \n above - normally
>
> foo = xyz;
> if (abc)
> ...
>
> implies the condition takes into account the previous line)
I will fix them in v3.
> [...]
>
>> + if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_STORAGE,
>> + QCOM_SCM_STORAGE_CMD))
>> + return;
>> +
>> + ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
>> + QCOM_SCM_STORAGE_GET_INFO,
>> + 0, &info, sizeof(info));
> I'm curious what happens if the call is available but SPINOR is not
> populated onboard..
>
> I thiiiink it should return STORAGE_RESULT_INVALID_PARAMETER but I'm not
> a 100% sure. Guess we'll see down the road.
Yes, on platforms I tested (QCS6490 LE), it returns
STORAGE_RESULT_INVALID_PARAMETER.
>> + if (ret < 0) {
>> + dev_warn(scm->dev, "scm storage get info failed: %d\n", ret);
>> + return;
>> + }
>> +
>> + total_blocks = le64_to_cpu(info.total_blocks);
>> + block_size = le32_to_cpu(info.block_size);
>> +
>> + dev_dbg(scm->dev, "scm storage size %llu bytes\n",
>> + total_blocks * block_size);
>> +
>> + storage_dev = platform_device_alloc("qcom_scm_storage", -1);
> -1 is PLATFORM_DEVID_NONE
>
> Let's use PLATFORM_DEVID_AUTO to allow potentially multiple instances of
> this driver being spawned down the road
I will change it to PLATFORM_DEVID_AUTO.
But will they really have multiple instances?
> Konrad
Thank you for the review, I will incorporate these changes in v3.
Best regards,
Junhao Xie
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v2 2/2] mtd: devices: Add Qualcomm SCM storage driver
2026-01-26 11:44 [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Junhao Xie
2026-01-26 11:44 ` [PATCH v2 1/2] firmware: qcom: scm: Add SCM storage interface support Junhao Xie
@ 2026-01-26 11:44 ` Junhao Xie
2026-01-29 19:01 ` Miquel Raynal
2026-01-28 13:26 ` [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Konrad Dybcio
` (2 subsequent siblings)
4 siblings, 1 reply; 20+ messages in thread
From: Junhao Xie @ 2026-01-26 11:44 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu, Junhao Xie
Add MTD driver for accessing storage devices managed by Qualcomm's
TrustZone firmware. On some platforms, BIOS/firmware storage (typically
SPI NOR flash) is not directly accessible from the non-secure world and
all operations must go through SCM (Secure Channel Manager) calls.
Signed-off-by: Junhao Xie <bigfoot@radxa.com>
Tested-by: Xilin Wu <sophon@radxa.com>
---
drivers/mtd/devices/Kconfig | 17 +++
drivers/mtd/devices/Makefile | 1 +
drivers/mtd/devices/qcom_scm_storage.c | 265 +++++++++++++++++++++++++++++++++
3 files changed, 283 insertions(+)
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index e518dfeee..4f73e89a1 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -194,6 +194,23 @@ config MTD_INTEL_DG
To compile this driver as a module, choose M here: the module
will be called mtd-intel-dg.
+config MTD_QCOM_SCM_STORAGE
+ tristate "Qualcomm TrustZone protected storage MTD driver"
+ depends on MTD
+ depends on QCOM_SCM || COMPILE_TEST
+ help
+ This provides an MTD device to access storage (typically SPI NOR
+ flash) that is managed by Qualcomm's TrustZone firmware. On some
+ platforms, the firmware storage is not directly accessible from
+ the non-secure world and all operations must go through secure
+ monitor calls.
+
+ This driver is only functional on devices where the bootloader
+ has configured TrustZone to expose the storage interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called qcom_scm_storage.
+
comment "Disk-On-Chip Device Drivers"
config MTD_DOCG3
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 9fe4ce9cf..d71d07f81 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
obj-$(CONFIG_MTD_ST_SPI_FSM) += st_spi_fsm.o
obj-$(CONFIG_MTD_POWERNV_FLASH) += powernv_flash.o
obj-$(CONFIG_MTD_INTEL_DG) += mtd_intel_dg.o
+obj-$(CONFIG_MTD_QCOM_SCM_STORAGE) += qcom_scm_storage.o
CFLAGS_docg3.o += -I$(src)
diff --git a/drivers/mtd/devices/qcom_scm_storage.c b/drivers/mtd/devices/qcom_scm_storage.c
new file mode 100644
index 000000000..bc3f40424
--- /dev/null
+++ b/drivers/mtd/devices/qcom_scm_storage.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Qualcomm TrustZone SCM Storage Flash driver
+ *
+ * Copyright (c) 2025 Junhao Xie <bigfoot@radxa.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/firmware/qcom/qcom_scm.h>
+
+/*
+ * This driver provides MTD access to storage devices managed by Qualcomm's
+ * TrustZone firmware. The storage (typically SPI NOR flash) is not directly
+ * accessible from the non-secure world and all operations must go through
+ * SCM (Secure Channel Manager) calls.
+ *
+ * A bounce buffer is required because the interface requires
+ * block-aligned addresses and sizes
+ */
+struct qcom_scm_storage {
+ struct device *dev;
+ struct mutex lock; /* Protects SCM storage operations */
+ struct mtd_info mtd;
+ struct qcom_scm_storage_info info;
+ size_t buffer_size;
+ u8 *buffer;
+};
+
+static int qcom_scm_storage_erase(struct mtd_info *mtd,
+ struct erase_info *instr)
+{
+ struct qcom_scm_storage *host = mtd->priv;
+ size_t block_size;
+
+ if (instr->addr % host->mtd.erasesize ||
+ instr->len % host->mtd.erasesize)
+ return -EINVAL;
+
+ block_size = le32_to_cpu(host->info.block_size);
+
+ guard(mutex)(&host->lock);
+
+ return qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
+ QCOM_SCM_STORAGE_ERASE,
+ instr->addr / block_size,
+ 0, instr->len);
+}
+
+static int qcom_scm_storage_read(struct mtd_info *mtd,
+ loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct qcom_scm_storage *host = mtd->priv;
+ loff_t block_start, block_off, lba;
+ size_t block_size, chunk, to_read;
+ int ret;
+
+ if (retlen)
+ *retlen = 0;
+
+ if (from + len > mtd->size)
+ return -EINVAL;
+
+ if (len == 0)
+ return 0;
+
+ block_size = le32_to_cpu(host->info.block_size);
+
+ guard(mutex)(&host->lock);
+
+ while (len > 0) {
+ block_start = round_down(from, block_size);
+ block_off = from - block_start;
+ lba = block_start / block_size;
+
+ if (block_off || len < block_size) {
+ chunk = min_t(size_t, block_size - block_off, len);
+ to_read = block_size;
+ } else {
+ chunk = round_down(len, block_size);
+ chunk = min_t(size_t, chunk, host->buffer_size);
+ to_read = chunk;
+ }
+
+ ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
+ QCOM_SCM_STORAGE_READ,
+ lba, host->buffer,
+ to_read);
+ if (ret)
+ return ret;
+
+ memcpy(buf, host->buffer + block_off, chunk);
+
+ buf += chunk;
+ from += chunk;
+ len -= chunk;
+ if (retlen)
+ *retlen += chunk;
+ }
+
+ return 0;
+}
+
+static int qcom_scm_storage_write(struct mtd_info *mtd,
+ loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct qcom_scm_storage *host = mtd->priv;
+ loff_t block_start, block_off, lba;
+ size_t block_size, chunk, to_write;
+ int ret;
+
+ if (retlen)
+ *retlen = 0;
+
+ if (to + len > mtd->size)
+ return -EINVAL;
+
+ if (len == 0)
+ return 0;
+
+ block_size = le32_to_cpu(host->info.block_size);
+
+ guard(mutex)(&host->lock);
+
+ while (len > 0) {
+ block_start = round_down(to, block_size);
+ block_off = to - block_start;
+ lba = block_start / block_size;
+
+ if (block_off || len < block_size) {
+ chunk = min_t(size_t, block_size - block_off, len);
+ to_write = block_size;
+
+ ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
+ QCOM_SCM_STORAGE_READ,
+ lba, host->buffer,
+ block_size);
+ if (ret)
+ return ret;
+ } else {
+ chunk = round_down(len, block_size);
+ chunk = min_t(size_t, chunk, host->buffer_size);
+ to_write = chunk;
+ }
+
+ memcpy(host->buffer + block_off, buf, chunk);
+
+ ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
+ QCOM_SCM_STORAGE_WRITE,
+ lba, host->buffer,
+ to_write);
+ if (ret)
+ return ret;
+
+ buf += chunk;
+ to += chunk;
+ len -= chunk;
+ if (retlen)
+ *retlen += chunk;
+ }
+
+ return 0;
+}
+
+static int qcom_scm_storage_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct qcom_scm_storage *host;
+ u64 total_blocks, serial_num;
+ u32 block_size;
+ int ret;
+
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, host);
+ host->dev = dev;
+
+ ret = devm_mutex_init(dev, &host->lock);
+ if (ret)
+ return ret;
+
+ host->buffer_size = SZ_256K;
+ host->buffer = devm_kzalloc(dev, host->buffer_size, GFP_KERNEL);
+ if (!host->buffer)
+ return -ENOMEM;
+
+ ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
+ QCOM_SCM_STORAGE_GET_INFO,
+ 0, &host->info,
+ sizeof(host->info));
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to get storage info\n");
+
+ total_blocks = le64_to_cpu(host->info.total_blocks);
+ serial_num = le64_to_cpu(host->info.serial_num);
+ block_size = le32_to_cpu(host->info.block_size);
+
+ if (!block_size || !total_blocks)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid storage geometry\n");
+
+ if (block_size > host->buffer_size)
+ return dev_err_probe(dev, -EINVAL,
+ "block size %u exceeds buffer size\n",
+ block_size);
+
+ host->mtd.priv = host;
+ host->mtd.name = dev_name(dev);
+ host->mtd.owner = THIS_MODULE;
+ host->mtd.dev.parent = dev;
+ host->mtd.size = total_blocks * block_size;
+ host->mtd.erasesize = block_size;
+ host->mtd.writesize = block_size;
+ host->mtd.writebufsize = block_size;
+ host->mtd.type = MTD_NORFLASH;
+ host->mtd.flags = MTD_WRITEABLE;
+ host->mtd._erase = qcom_scm_storage_erase;
+ host->mtd._read = qcom_scm_storage_read;
+ host->mtd._write = qcom_scm_storage_write;
+
+ ret = mtd_device_register(&host->mtd, NULL, 0);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "scm storage 0x%llx registered with size %llu bytes\n",
+ serial_num, host->mtd.size);
+
+ return 0;
+}
+
+static void qcom_scm_storage_remove(struct platform_device *pdev)
+{
+ struct qcom_scm_storage *host = platform_get_drvdata(pdev);
+
+ WARN_ON(mtd_device_unregister(&host->mtd));
+}
+
+static const struct platform_device_id qcom_scm_storage_ids[] = {
+ { "qcom_scm_storage", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, qcom_scm_storage_ids);
+
+static struct platform_driver qcom_scm_storage_driver = {
+ .probe = qcom_scm_storage_probe,
+ .remove = qcom_scm_storage_remove,
+ .driver = {
+ .name = "qcom_scm_storage",
+ },
+ .id_table = qcom_scm_storage_ids,
+};
+module_platform_driver(qcom_scm_storage_driver);
+
+MODULE_AUTHOR("Junhao Xie <bigfoot@radxa.com>");
+MODULE_DESCRIPTION("Qualcomm TrustZone SCM Storage Flash driver");
+MODULE_LICENSE("GPL");
--
2.52.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH v2 2/2] mtd: devices: Add Qualcomm SCM storage driver
2026-01-26 11:44 ` [PATCH v2 2/2] mtd: devices: Add Qualcomm SCM storage driver Junhao Xie
@ 2026-01-29 19:01 ` Miquel Raynal
0 siblings, 0 replies; 20+ messages in thread
From: Miquel Raynal @ 2026-01-29 19:01 UTC (permalink / raw)
To: Junhao Xie
Cc: Bjorn Andersson, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
Hello Junhao,
> +static int qcom_scm_storage_erase(struct mtd_info *mtd,
> + struct erase_info *instr)
> +{
> + struct qcom_scm_storage *host = mtd->priv;
> + size_t block_size;
> +
> + if (instr->addr % host->mtd.erasesize ||
> + instr->len % host->mtd.erasesize)
> + return -EINVAL;
Can theses situations realistically happen? Erases are in theory
eraseblock aligned, so I doubt this case shall be checked in device drivers.
> +
> + block_size = le32_to_cpu(host->info.block_size);
You seem to store the SCM info structure as-is and always make
conversions on the fly. May I suggest to store the fields you need
directly in the correct format/endianness?
> +
> + guard(mutex)(&host->lock);
> +
> + return qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
> + QCOM_SCM_STORAGE_ERASE,
> + instr->addr / block_size,
Actually what you need instead of block_size is to use mtd->erasesize
directly, no need to store "block_size" in your structure, you already
have it.
> + 0, instr->len);
> +}
> +
> +static int qcom_scm_storage_read(struct mtd_info *mtd,
> + loff_t from, size_t len,
> + size_t *retlen, u_char *buf)
u_char? Can we use a more common type?
> +{
> + struct qcom_scm_storage *host = mtd->priv;
> + loff_t block_start, block_off, lba;
> + size_t block_size, chunk, to_read;
> + int ret;
> +
> + if (retlen)
> + *retlen = 0;
Are there cases where retlen can be absent?
> +
> + if (from + len > mtd->size)
> + return -EINVAL;
This check should be done at the core level already.
> + if (len == 0)
> + return 0;
Ditto (see mtdchar_read()).
> + block_size = le32_to_cpu(host->info.block_size);
> +
> + guard(mutex)(&host->lock);
> +
> + while (len > 0) {
> + block_start = round_down(from, block_size);
> + block_off = from - block_start;
> + lba = block_start / block_size;
> +
> + if (block_off || len < block_size) {
> + chunk = min_t(size_t, block_size - block_off, len);
> + to_read = block_size;
> + } else {
> + chunk = round_down(len, block_size);
> + chunk = min_t(size_t, chunk, host->buffer_size);
> + to_read = chunk;
> + }
> +
> + ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
> + QCOM_SCM_STORAGE_READ,
> + lba, host->buffer,
> + to_read);
> + if (ret)
> + return ret;
> +
> + memcpy(buf, host->buffer + block_off, chunk);
> +
> + buf += chunk;
> + from += chunk;
> + len -= chunk;
> + if (retlen)
> + *retlen += chunk;
> + }
> +
> + return 0;
> +}
> +
> +static int qcom_scm_storage_write(struct mtd_info *mtd,
> + loff_t to, size_t len,
> + size_t *retlen, const u_char *buf)
> +{
> + struct qcom_scm_storage *host = mtd->priv;
> + loff_t block_start, block_off, lba;
> + size_t block_size, chunk, to_write;
> + int ret;
> +
> + if (retlen)
> + *retlen = 0;
> +
> + if (to + len > mtd->size)
> + return -EINVAL;
> +
> + if (len == 0)
> + return 0;
> +
> + block_size = le32_to_cpu(host->info.block_size);
> +
> + guard(mutex)(&host->lock);
> +
> + while (len > 0) {
> + block_start = round_down(to, block_size);
> + block_off = to - block_start;
> + lba = block_start / block_size;
> +
> + if (block_off || len < block_size) {
> + chunk = min_t(size_t, block_size - block_off, len);
> + to_write = block_size;
> +
> + ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
> + QCOM_SCM_STORAGE_READ,
> + lba, host->buffer,
> + block_size);
This is strange. Does it really work? My understanding: you're trying to
handle a non aligned write access (I'm not even sure this is possible as
you set writesize == erasesize) by reading the existing data before
writing. If that's what you intend to do, you'll forcibly get 1s instead
of actual data because erases are mandatory before writes, which means
your read will happen too late.
I might be totally wrong, but I believe this approach is
incorrect. Please explain what you're trying to do otherwise.
> + if (ret)
> + return ret;
> + } else {
> + chunk = round_down(len, block_size);
> + chunk = min_t(size_t, chunk, host->buffer_size);
> + to_write = chunk;
> + }
> +
> + memcpy(host->buffer + block_off, buf, chunk);
> +
> + ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
> + QCOM_SCM_STORAGE_WRITE,
> + lba, host->buffer,
> + to_write);
> + if (ret)
> + return ret;
> +
> + buf += chunk;
> + to += chunk;
> + len -= chunk;
> + if (retlen)
> + *retlen += chunk;
> + }
> +
> + return 0;
> +}
> +
> +static int qcom_scm_storage_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct qcom_scm_storage *host;
> + u64 total_blocks, serial_num;
> + u32 block_size;
> + int ret;
> +
> + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
> + if (!host)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, host);
> + host->dev = dev;
> +
> + ret = devm_mutex_init(dev, &host->lock);
> + if (ret)
> + return ret;
> +
> + host->buffer_size = SZ_256K;
> + host->buffer = devm_kzalloc(dev, host->buffer_size, GFP_KERNEL);
Do you really need 256K of adjacent memory? If this is a DMA-able
buffer, then yes. Also, the check (block_size vs. buffer_size) should
happen before this allocation, and you should not need to allocate 256k
blindly, just use the NOR geometry knowledge.
> + if (!host->buffer)
> + return -ENOMEM;
> +
> + ret = qcom_scm_storage_send_cmd(QCOM_SCM_STORAGE_SPINOR,
> + QCOM_SCM_STORAGE_GET_INFO,
> + 0, &host->info,
> + sizeof(host->info));
> + if (ret < 0)
> + return dev_err_probe(dev, ret,
> + "failed to get storage info\n");
Maybe this print can be enhanced, it may also mean the firmware does not
implement the required system call?
> +
> + total_blocks = le64_to_cpu(host->info.total_blocks);
> + serial_num = le64_to_cpu(host->info.serial_num);
> + block_size = le32_to_cpu(host->info.block_size);
> +
> + if (!block_size || !total_blocks)
> + return dev_err_probe(dev, -EINVAL,
> + "invalid storage geometry\n");
> +
> + if (block_size > host->buffer_size)
> + return dev_err_probe(dev, -EINVAL,
> + "block size %u exceeds buffer size\n",
> + block_size);
I am now in favour of reducing logs in the kernel, maybe you can group
these two prints into one, indicating the info you get from firmware is
incorrect? Also, what is the point of using dev_err_probe() here, as you
cannot have an EPROBE_DEFER?
> +
> + host->mtd.priv = host;
> + host->mtd.name = dev_name(dev);
> + host->mtd.owner = THIS_MODULE;
> + host->mtd.dev.parent = dev;
> + host->mtd.size = total_blocks * block_size;
> + host->mtd.erasesize = block_size;
> + host->mtd.writesize = block_size;
> + host->mtd.writebufsize = block_size;
> + host->mtd.type = MTD_NORFLASH;
> + host->mtd.flags = MTD_WRITEABLE;
> + host->mtd._erase = qcom_scm_storage_erase;
> + host->mtd._read = qcom_scm_storage_read;
> + host->mtd._write = qcom_scm_storage_write;
> +
> + dev_info(dev, "scm storage 0x%llx registered with size %llu bytes\n",
> + serial_num, host->mtd.size);
Please drop this message, it is not useful.
...
> +static struct platform_driver qcom_scm_storage_driver = {
> + .probe = qcom_scm_storage_probe,
> + .remove = qcom_scm_storage_remove,
> + .driver = {
> + .name = "qcom_scm_storage",
> + },
> + .id_table = qcom_scm_storage_ids,
I am surprised you have an id_table here, this is likely not for an OF
based platform, do you confirm?
Thanks,
Miquèl
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-26 11:44 [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Junhao Xie
2026-01-26 11:44 ` [PATCH v2 1/2] firmware: qcom: scm: Add SCM storage interface support Junhao Xie
2026-01-26 11:44 ` [PATCH v2 2/2] mtd: devices: Add Qualcomm SCM storage driver Junhao Xie
@ 2026-01-28 13:26 ` Konrad Dybcio
2026-01-28 14:13 ` Miquel Raynal
2026-01-29 13:05 ` Junhao Xie
2026-01-28 20:42 ` Bjorn Andersson
2026-01-28 21:43 ` Trilok Soni
4 siblings, 2 replies; 20+ messages in thread
From: Konrad Dybcio @ 2026-01-28 13:26 UTC (permalink / raw)
To: Junhao Xie, Bjorn Andersson, Konrad Dybcio, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu
On 1/26/26 12:44 PM, Junhao Xie wrote:
> This patch series adds support for accessing storage devices managed by
> Qualcomm TrustZone firmware via SCM (Secure Channel Manager) by
> introducing a new MTD driver.
>
> On some Qualcomm platforms, firmware or BIOS-related storage (typically
> SPI NOR flash) is not directly accessible from the non-secure world.
> All read, write, and erase operations must be performed through SCM
> interfaces provided by the secure firmware. As a result, existing MTD
> SPI NOR drivers cannot be used directly on these systems.
>
> This series introduces a new MTD device driver that exposes such
> firmware-managed storage as a standard MTD device in the Linux kernel.
> The driver is built on top of the existing Qualcomm SCM infrastructure
> and integrates with the MTD subsystem to provide a uniform interface to
> userspace.
[...]
> Junhao Xie (2):
> firmware: qcom: scm: Add SCM storage interface support
> mtd: devices: Add Qualcomm SCM storage driver
>
> drivers/firmware/qcom/qcom_scm.c | 161 ++++++++++++++++++++
> drivers/firmware/qcom/qcom_scm.h | 3 +
> drivers/mtd/devices/Kconfig | 17 +++
> drivers/mtd/devices/Makefile | 1 +
> drivers/mtd/devices/qcom_scm_storage.c | 265 +++++++++++++++++++++++++++++++++
> include/linux/firmware/qcom/qcom_scm.h | 34 +++++
> 6 files changed, 481 insertions(+)
> ---
> base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
This is 6.19-rc7, please rebase on linux-next/master (the series
doesn't currently apply because this base is essentially a full release
behind)
Konrad
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-28 13:26 ` [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Konrad Dybcio
@ 2026-01-28 14:13 ` Miquel Raynal
2026-01-28 20:31 ` Bjorn Andersson
2026-01-29 13:05 ` Junhao Xie
1 sibling, 1 reply; 20+ messages in thread
From: Miquel Raynal @ 2026-01-28 14:13 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Junhao Xie, Bjorn Andersson, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
Hello,
>> Junhao Xie (2):
>> firmware: qcom: scm: Add SCM storage interface support
>> mtd: devices: Add Qualcomm SCM storage driver
>>
>> drivers/firmware/qcom/qcom_scm.c | 161 ++++++++++++++++++++
>> drivers/firmware/qcom/qcom_scm.h | 3 +
>> drivers/mtd/devices/Kconfig | 17 +++
>> drivers/mtd/devices/Makefile | 1 +
>> drivers/mtd/devices/qcom_scm_storage.c | 265 +++++++++++++++++++++++++++++++++
>> include/linux/firmware/qcom/qcom_scm.h | 34 +++++
>> 6 files changed, 481 insertions(+)
>> ---
>> base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
>
> This is 6.19-rc7, please rebase on linux-next/master (the series
> doesn't currently apply because this base is essentially a full release
> behind)
If I may, I even skipped the mail entirely because it was not about mtd
in the end. There is a single big patch labelled "firmware: qcom:". I
believe the series would better be split in smaller chunks. Typically
one for the storage support and another one for the firmware part, at
least.
Thanks,
Miquèl
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-28 14:13 ` Miquel Raynal
@ 2026-01-28 20:31 ` Bjorn Andersson
2026-01-29 18:38 ` Miquel Raynal
0 siblings, 1 reply; 20+ messages in thread
From: Bjorn Andersson @ 2026-01-28 20:31 UTC (permalink / raw)
To: Miquel Raynal
Cc: Konrad Dybcio, Junhao Xie, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
On Wed, Jan 28, 2026 at 03:13:59PM +0100, Miquel Raynal wrote:
> Hello,
>
> >> Junhao Xie (2):
> >> firmware: qcom: scm: Add SCM storage interface support
> >> mtd: devices: Add Qualcomm SCM storage driver
> >>
> >> drivers/firmware/qcom/qcom_scm.c | 161 ++++++++++++++++++++
> >> drivers/firmware/qcom/qcom_scm.h | 3 +
> >> drivers/mtd/devices/Kconfig | 17 +++
> >> drivers/mtd/devices/Makefile | 1 +
> >> drivers/mtd/devices/qcom_scm_storage.c | 265 +++++++++++++++++++++++++++++++++
> >> include/linux/firmware/qcom/qcom_scm.h | 34 +++++
> >> 6 files changed, 481 insertions(+)
> >> ---
> >> base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
> >
> > This is 6.19-rc7, please rebase on linux-next/master (the series
> > doesn't currently apply because this base is essentially a full release
> > behind)
>
> If I may, I even skipped the mail entirely because it was not about mtd
> in the end. There is a single big patch labelled "firmware: qcom:". I
> believe the series would better be split in smaller chunks. Typically
> one for the storage support and another one for the firmware part, at
> least.
>
The firmware patch adds wrappers for the secure world interface, which
without the MTD driver will lack consumers of the API - i.e. I'd prefer
not to pick that part, or parts thereof, alone.
So I think it does make sense to introduce the two parts together in one
series (if you have any requests for splitting the MTD patch up in any
way I have no objections).
This leaves us with the practical problem of getting it merged, which I
believe would best be handled by me picking the firmware patch and
sharing this in an immutable branch with you, once we're happy with the
set (which won't be for 6.20).
I hope you're okay with such plan?
Regards,
Bjorn
> Thanks,
> Miquèl
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-28 20:31 ` Bjorn Andersson
@ 2026-01-29 18:38 ` Miquel Raynal
0 siblings, 0 replies; 20+ messages in thread
From: Miquel Raynal @ 2026-01-29 18:38 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Konrad Dybcio, Junhao Xie, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
Hello Bjorn,
>> If I may, I even skipped the mail entirely because it was not about mtd
>> in the end. There is a single big patch labelled "firmware: qcom:". I
>> believe the series would better be split in smaller chunks. Typically
>> one for the storage support and another one for the firmware part, at
>> least.
>>
>
> The firmware patch adds wrappers for the secure world interface, which
> without the MTD driver will lack consumers of the API - i.e. I'd prefer
> not to pick that part, or parts thereof, alone.
Yes, I understand.
> So I think it does make sense to introduce the two parts together in one
> series (if you have any requests for splitting the MTD patch up in any
> way I have no objections).
>
> This leaves us with the practical problem of getting it merged, which I
> believe would best be handled by me picking the firmware patch and
> sharing this in an immutable branch with you, once we're happy with the
> set (which won't be for 6.20).
Works for me!
I'll send a minor review with a couple of comments, but we can apply
this close after next -rc1, if you are good with the fw part.
Thanks,
Miquèl
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-28 13:26 ` [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Konrad Dybcio
2026-01-28 14:13 ` Miquel Raynal
@ 2026-01-29 13:05 ` Junhao Xie
1 sibling, 0 replies; 20+ messages in thread
From: Junhao Xie @ 2026-01-29 13:05 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Konrad Dybcio, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu, Junhao Xie
On 2026/1/28 21:26, Konrad Dybcio wrote:
> On 1/26/26 12:44 PM, Junhao Xie wrote:
>> Junhao Xie (2):
>> firmware: qcom: scm: Add SCM storage interface support
>> mtd: devices: Add Qualcomm SCM storage driver
>>
>> drivers/firmware/qcom/qcom_scm.c | 161 ++++++++++++++++++++
>> drivers/firmware/qcom/qcom_scm.h | 3 +
>> drivers/mtd/devices/Kconfig | 17 +++
>> drivers/mtd/devices/Makefile | 1 +
>> drivers/mtd/devices/qcom_scm_storage.c | 265 +++++++++++++++++++++++++++++++++
>> include/linux/firmware/qcom/qcom_scm.h | 34 +++++
>> 6 files changed, 481 insertions(+)
>> ---
>> base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
> This is 6.19-rc7, please rebase on linux-next/master (the series
> doesn't currently apply because this base is essentially a full release
> behind)
I will rebase the series onto linux-next/master in v3.
> Konrad
Best regards,
Junhao Xie
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-26 11:44 [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Junhao Xie
` (2 preceding siblings ...)
2026-01-28 13:26 ` [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Konrad Dybcio
@ 2026-01-28 20:42 ` Bjorn Andersson
2026-01-30 13:39 ` Junhao Xie
2026-01-28 21:43 ` Trilok Soni
4 siblings, 1 reply; 20+ messages in thread
From: Bjorn Andersson @ 2026-01-28 20:42 UTC (permalink / raw)
To: Junhao Xie
Cc: Konrad Dybcio, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
On Mon, Jan 26, 2026 at 07:44:50PM +0800, Junhao Xie wrote:
> This patch series adds support for accessing storage devices managed by
> Qualcomm TrustZone firmware via SCM (Secure Channel Manager) by
> introducing a new MTD driver.
>
> On some Qualcomm platforms, firmware or BIOS-related storage (typically
> SPI NOR flash) is not directly accessible from the non-secure world.
> All read, write, and erase operations must be performed through SCM
> interfaces provided by the secure firmware. As a result, existing MTD
> SPI NOR drivers cannot be used directly on these systems.
>
> This series introduces a new MTD device driver that exposes such
> firmware-managed storage as a standard MTD device in the Linux kernel.
> The driver is built on top of the existing Qualcomm SCM infrastructure
> and integrates with the MTD subsystem to provide a uniform interface to
> userspace.
>
> This driver has been tested on Radxa Dragon Q6A, based on the Qualcomm
> QCS6490 SoC, with a Winbond W25Q256JWPIQ SPI NOR flash device.
>
> Note that this platform previously used the standard Qualcomm Linux
> firmware, which allowed direct access to the QSPI controller without
> needing this driver. However, we plan to migrate to a Windows-compatible
> firmware which is more feature-complete but restricts direct access.
> Device tree changes for this transition will be sent separately.
>
> If kernel boots with EL2, access to the SCM storage will be denied. This
> needs more investigation.
>
Sorry, I missed your reply to me on v1.
You replied that this allow your users to update "BIOS" firmware
directly from Linux, which I can see being more convenient than relying
on UEFI update capsules, in particular in a development environment.
The concern I have with this is that I don't think an end-user of such
system, has a way to recover from breaking the content on their SPI-NOR.
As such, exposing such a convenient interface for the end-user to brick
their devices is probably not a good idea.
I think we should somehow lock the interface down to be read-only by
default, and perhaps have some mechanism to unlock the write mode (like
a module parameter expecting the sentence "YES, I DO HAVE THE FIREHOSE
PROGRAMMER FOR THIS BOARD").
I don't believe you answered my question regarding how to access this
interface from the kernel. On many of these devices we can find the MAC
addresses of the system in the "DPP" partition. Do you have any ideas
about how we could access this from within the kernel?
Regards,
Bjorn
> Changes in v2:
> - Convert enum qcom_scm_storage_result to macro definitions
> - Use __qcom_scm_is_call_available() instead of a machine allowlist
> - Add missing __packed annotations and endianness handling
> - Introduce struct qcom_scm_storage_payload to improve readability
> - Always compiled-in qcom_scm_storage_send_cmd() and qcom_scm_storage_init()
> https://lore.kernel.org/lkml/F138514E18CB55B6+20251218180205.930961-1-bigfoot@radxa.com/
>
> Tested-by: Xilin Wu <sophon@radxa.com>
> Signed-off-by: Junhao Xie <bigfoot@radxa.com>
> ---
> Junhao Xie (2):
> firmware: qcom: scm: Add SCM storage interface support
> mtd: devices: Add Qualcomm SCM storage driver
>
> drivers/firmware/qcom/qcom_scm.c | 161 ++++++++++++++++++++
> drivers/firmware/qcom/qcom_scm.h | 3 +
> drivers/mtd/devices/Kconfig | 17 +++
> drivers/mtd/devices/Makefile | 1 +
> drivers/mtd/devices/qcom_scm_storage.c | 265 +++++++++++++++++++++++++++++++++
> include/linux/firmware/qcom/qcom_scm.h | 34 +++++
> 6 files changed, 481 insertions(+)
> ---
> base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
> change-id: 20260126-scm-storage-v2-0a4f3e900b88
>
> Best regards,
> --
> Junhao Xie <bigfoot@radxa.com>
>
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-28 20:42 ` Bjorn Andersson
@ 2026-01-30 13:39 ` Junhao Xie
2026-01-30 14:10 ` Miquel Raynal
0 siblings, 1 reply; 20+ messages in thread
From: Junhao Xie @ 2026-01-30 13:39 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Konrad Dybcio, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu, Junhao Xie
On 2026/1/29 4:42, Bjorn Andersson wrote:
> On Mon, Jan 26, 2026 at 07:44:50PM +0800, Junhao Xie wrote:
>> This patch series adds support for accessing storage devices managed by
>> Qualcomm TrustZone firmware via SCM (Secure Channel Manager) by
>> introducing a new MTD driver.
>>
>> On some Qualcomm platforms, firmware or BIOS-related storage (typically
>> SPI NOR flash) is not directly accessible from the non-secure world.
>> All read, write, and erase operations must be performed through SCM
>> interfaces provided by the secure firmware. As a result, existing MTD
>> SPI NOR drivers cannot be used directly on these systems.
>>
>> This series introduces a new MTD device driver that exposes such
>> firmware-managed storage as a standard MTD device in the Linux kernel.
>> The driver is built on top of the existing Qualcomm SCM infrastructure
>> and integrates with the MTD subsystem to provide a uniform interface to
>> userspace.
>>
>> This driver has been tested on Radxa Dragon Q6A, based on the Qualcomm
>> QCS6490 SoC, with a Winbond W25Q256JWPIQ SPI NOR flash device.
>>
>> Note that this platform previously used the standard Qualcomm Linux
>> firmware, which allowed direct access to the QSPI controller without
>> needing this driver. However, we plan to migrate to a Windows-compatible
>> firmware which is more feature-complete but restricts direct access.
>> Device tree changes for this transition will be sent separately.
>>
>> If kernel boots with EL2, access to the SCM storage will be denied. This
>> needs more investigation.
>>
> Sorry, I missed your reply to me on v1.
>
>
> You replied that this allow your users to update "BIOS" firmware
> directly from Linux, which I can see being more convenient than relying
> on UEFI update capsules, in particular in a development environment.
>
> The concern I have with this is that I don't think an end-user of such
> system, has a way to recover from breaking the content on their SPI-NOR.
>
> As such, exposing such a convenient interface for the end-user to brick
> their devices is probably not a good idea.
>
> I think we should somehow lock the interface down to be read-only by
> default, and perhaps have some mechanism to unlock the write mode (like
> a module parameter expecting the sentence "YES, I DO HAVE THE FIREHOSE
> PROGRAMMER FOR THIS BOARD").
>
>
> I don't believe you answered my question regarding how to access this
> interface from the kernel. On many of these devices we can find the MAC
> addresses of the system in the "DPP" partition. Do you have any ideas
> about how we could access this from within the kernel?
>
> Regards,
> Bjorn
I agree with your point. I will add a module param in v3 for default
read-only mode. e.g.: /sys/module/qcom_scm_storage/parameters/allow_write
For something like the "DPP" partition, I think it's better to access it
from userspace than from kernel.
Best regards,
Junhao Xie
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-30 13:39 ` Junhao Xie
@ 2026-01-30 14:10 ` Miquel Raynal
2026-01-30 16:45 ` Junhao Xie
0 siblings, 1 reply; 20+ messages in thread
From: Miquel Raynal @ 2026-01-30 14:10 UTC (permalink / raw)
To: Junhao Xie
Cc: Bjorn Andersson, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
Hi,
>> I don't believe you answered my question regarding how to access this
>> interface from the kernel. On many of these devices we can find the MAC
>> addresses of the system in the "DPP" partition. Do you have any ideas
>> about how we could access this from within the kernel?
>>
>> Regards,
>> Bjorn
>
> I agree with your point. I will add a module param in v3 for default
> read-only mode. e.g.: /sys/module/qcom_scm_storage/parameters/allow_write
>
> For something like the "DPP" partition, I think it's better to access it
> from userspace than from kernel.
If it's a MAC address that you are accessing, direct userspace does not
sound like a good fit. If I may, NVMEM cells are there exactly for this
purpose: identifying the content of a subpart of a storage device in a
storage agnostic way. The NVMEM cells are made available to in-kernel
drivers (ie. network devices have all the infrastructure to get the MAC
address from there) and their content is also exposed to userspace
through sysfs now.
Thanks,
Miquèl
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-30 14:10 ` Miquel Raynal
@ 2026-01-30 16:45 ` Junhao Xie
2026-02-03 14:20 ` Miquel Raynal
0 siblings, 1 reply; 20+ messages in thread
From: Junhao Xie @ 2026-01-30 16:45 UTC (permalink / raw)
To: Miquel Raynal
Cc: Bjorn Andersson, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu, Junhao Xie
On 2026/1/30 22:10, Miquel Raynal wrote:
> Hi,
>
>>> I don't believe you answered my question regarding how to access this
>>> interface from the kernel. On many of these devices we can find the MAC
>>> addresses of the system in the "DPP" partition. Do you have any ideas
>>> about how we could access this from within the kernel?
>>>
>>> Regards,
>>> Bjorn
>> I agree with your point. I will add a module param in v3 for default
>> read-only mode. e.g.: /sys/module/qcom_scm_storage/parameters/allow_write
>>
>> For something like the "DPP" partition, I think it's better to access it
>> from userspace than from kernel.
> If it's a MAC address that you are accessing, direct userspace does not
> sound like a good fit. If I may, NVMEM cells are there exactly for this
> purpose: identifying the content of a subpart of a storage device in a
> storage agnostic way. The NVMEM cells are made available to in-kernel
> drivers (ie. network devices have all the infrastructure to get the MAC
> address from there) and their content is also exposed to userspace
> through sysfs now.
Qualcomm's SPI-NOR boot firmware uses a GPT partition table. The "DPP"
partition contains a FAT file system, and the MAC address is stored in
one of these files.
Because the data is stored inside a filesystem rather than at a fixed
offset, it does not fit well with the NVMEM model, which assumes simple
offset-based access.
Accessing this would require the kernel to directly read files from a
filesystem, which is generally not appropriate, so this should probably
not be accessed from kernel.
> Thanks,
> Miquèl
Best regards,
Junhao Xie
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-30 16:45 ` Junhao Xie
@ 2026-02-03 14:20 ` Miquel Raynal
2026-03-13 10:16 ` Val Packett
0 siblings, 1 reply; 20+ messages in thread
From: Miquel Raynal @ 2026-02-03 14:20 UTC (permalink / raw)
To: Junhao Xie
Cc: Bjorn Andersson, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
>>> For something like the "DPP" partition, I think it's better to access it
>>> from userspace than from kernel.
>> If it's a MAC address that you are accessing, direct userspace does not
>> sound like a good fit. If I may, NVMEM cells are there exactly for this
>> purpose: identifying the content of a subpart of a storage device in a
>> storage agnostic way. The NVMEM cells are made available to in-kernel
>> drivers (ie. network devices have all the infrastructure to get the MAC
>> address from there) and their content is also exposed to userspace
>> through sysfs now.
>
> Qualcomm's SPI-NOR boot firmware uses a GPT partition table. The "DPP"
> partition contains a FAT file system, and the MAC address is stored in
> one of these files.
>
> Because the data is stored inside a filesystem rather than at a fixed
> offset, it does not fit well with the NVMEM model, which assumes simple
> offset-based access.
Not anymore, there are nvmem layouts now that are much more
flexible, so if a network driver shall get this MAC address, it is still
doable.
Otherwise there is no such need, and in the case of a file in a FAT
filesystem, I guess it is preferable to use mtdblock/ubiblock in order
to expose a block device and mount it from userspace.
Please note that exposing a FAT filesystem on top of a SPI NOR is very
inappropriate. FAT is a block filesystem, not aware of all the MTD
specificities (like bad blocks).
Cheers,
Miquèl
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-02-03 14:20 ` Miquel Raynal
@ 2026-03-13 10:16 ` Val Packett
0 siblings, 0 replies; 20+ messages in thread
From: Val Packett @ 2026-03-13 10:16 UTC (permalink / raw)
To: Miquel Raynal, Junhao Xie
Cc: Bjorn Andersson, Konrad Dybcio, Richard Weinberger,
Vignesh Raghavendra, linux-arm-msm, linux-kernel, linux-mtd,
Xilin Wu
On 2/3/26 11:20 AM, Miquel Raynal wrote:
>>>> For something like the "DPP" partition, I think it's better to access it
>>>> from userspace than from kernel.
>>> If it's a MAC address that you are accessing, direct userspace does not
>>> sound like a good fit. If I may, NVMEM cells are there exactly for this
>>> purpose: identifying the content of a subpart of a storage device in a
>>> storage agnostic way. The NVMEM cells are made available to in-kernel
>>> drivers (ie. network devices have all the infrastructure to get the MAC
>>> address from there) and their content is also exposed to userspace
>>> through sysfs now.
>> Qualcomm's SPI-NOR boot firmware uses a GPT partition table. The "DPP"
>> partition contains a FAT file system, and the MAC address is stored in
>> one of these files.
>>
>> Because the data is stored inside a filesystem rather than at a fixed
>> offset, it does not fit well with the NVMEM model, which assumes simple
>> offset-based access.
> Not anymore, there are nvmem layouts now that are much more
> flexible, so if a network driver shall get this MAC address, it is still
> doable.
>
> Otherwise there is no such need, and in the case of a file in a FAT
> filesystem, I guess it is preferable to use mtdblock/ubiblock in order
> to expose a block device and mount it from userspace.
>
> Please note that exposing a FAT filesystem on top of a SPI NOR is very
> inappropriate. FAT is a block filesystem, not aware of all the MTD
> specificities (like bad blocks).
FWIW there is an existing widely used solution (workaround?) for the MAC
address: dtbloader reads the DPP partition in UEFI and applies the MAC
address as a DT fixup.
https://github.com/TravMurav/dtbloader/blob/493e7e82025edddab29fe99c2b6ec566f6e01ac1/src/qcom.c#L260
(But this means that any dtbloader alternative such as the systemd UKI
stub must also implement the same thing, which is not great.)
Reading that code, it does not seem to be a FAT filesystem exactly? It's
something called "RWFS" where files have 49-char long names and a
49-char "vendor" string field that's either "QCOM" or "OEM".
Also on the rare older devices that have SNOC WiFi/modem but NVMe
storage —basically the Surface Pro X— the modem partitions need to be
accessed from userspace (rmtfs) and they're stored on the NOR flash.
Well, at least in the WiFi-only case even blank files are enough to
replace them :) but for cellular I think the IMEI and stuff is there..
So this all sounds supremely annoying, we have a GPT partitioned flash
where some specific partitions should be given to the WiFi&BT drivers
(as nvmem cells?) but others should be accessible as mtdblock devices in
userspace >_<
~val
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-26 11:44 [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support Junhao Xie
` (3 preceding siblings ...)
2026-01-28 20:42 ` Bjorn Andersson
@ 2026-01-28 21:43 ` Trilok Soni
2026-01-29 12:47 ` Junhao Xie
4 siblings, 1 reply; 20+ messages in thread
From: Trilok Soni @ 2026-01-28 21:43 UTC (permalink / raw)
To: Junhao Xie, Bjorn Andersson, Konrad Dybcio, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu
On 1/26/2026 3:44 AM, Junhao Xie wrote:
> This patch series adds support for accessing storage devices managed by
> Qualcomm TrustZone firmware via SCM (Secure Channel Manager) by
> introducing a new MTD driver.
>
> On some Qualcomm platforms, firmware or BIOS-related storage (typically
> SPI NOR flash) is not directly accessible from the non-secure world.
> All read, write, and erase operations must be performed through SCM
> interfaces provided by the secure firmware. As a result, existing MTD
> SPI NOR drivers cannot be used directly on these systems.
>
> This series introduces a new MTD device driver that exposes such
> firmware-managed storage as a standard MTD device in the Linux kernel.
> The driver is built on top of the existing Qualcomm SCM infrastructure
> and integrates with the MTD subsystem to provide a uniform interface to
> userspace.
>
> This driver has been tested on Radxa Dragon Q6A, based on the Qualcomm
> QCS6490 SoC, with a Winbond W25Q256JWPIQ SPI NOR flash device.
>
> Note that this platform previously used the standard Qualcomm Linux
> firmware, which allowed direct access to the QSPI controller without
> needing this driver. However, we plan to migrate to a Windows-compatible
> firmware which is more feature-complete but restricts direct access.
> Device tree changes for this transition will be sent separately.
>
> If kernel boots with EL2, access to the SCM storage will be denied. This
> needs more investigation.
So you plan to enable this driver only w/ the Gunyah based configuration
and disable for the KVM one through the devicetree overlay ? I just
don't want to break the KVM boot flow on other platforms supporting
qcs6490.
>
> Changes in v2:
> - Convert enum qcom_scm_storage_result to macro definitions
> - Use __qcom_scm_is_call_available() instead of a machine allowlist
> - Add missing __packed annotations and endianness handling
> - Introduce struct qcom_scm_storage_payload to improve readability
> - Always compiled-in qcom_scm_storage_send_cmd() and qcom_scm_storage_init()
> https://lore.kernel.org/lkml/F138514E18CB55B6+20251218180205.930961-1-bigfoot@radxa.com/
>
> Tested-by: Xilin Wu <sophon@radxa.com>
> Signed-off-by: Junhao Xie <bigfoot@radxa.com>
> ---
> Junhao Xie (2):
> firmware: qcom: scm: Add SCM storage interface support
> mtd: devices: Add Qualcomm SCM storage driver
>
> drivers/firmware/qcom/qcom_scm.c | 161 ++++++++++++++++++++
> drivers/firmware/qcom/qcom_scm.h | 3 +
> drivers/mtd/devices/Kconfig | 17 +++
> drivers/mtd/devices/Makefile | 1 +
> drivers/mtd/devices/qcom_scm_storage.c | 265 +++++++++++++++++++++++++++++++++
> include/linux/firmware/qcom/qcom_scm.h | 34 +++++
> 6 files changed, 481 insertions(+)
> ---
> base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
> change-id: 20260126-scm-storage-v2-0a4f3e900b88
>
> Best regards,
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-28 21:43 ` Trilok Soni
@ 2026-01-29 12:47 ` Junhao Xie
2026-01-29 14:17 ` Konrad Dybcio
0 siblings, 1 reply; 20+ messages in thread
From: Junhao Xie @ 2026-01-29 12:47 UTC (permalink / raw)
To: Trilok Soni, Bjorn Andersson, Konrad Dybcio, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu
On 2026/1/29 5:43, Trilok Soni wrote:
> On 1/26/2026 3:44 AM, Junhao Xie wrote:
>> This patch series adds support for accessing storage devices managed by
>> Qualcomm TrustZone firmware via SCM (Secure Channel Manager) by
>> introducing a new MTD driver.
>>
>> On some Qualcomm platforms, firmware or BIOS-related storage (typically
>> SPI NOR flash) is not directly accessible from the non-secure world.
>> All read, write, and erase operations must be performed through SCM
>> interfaces provided by the secure firmware. As a result, existing MTD
>> SPI NOR drivers cannot be used directly on these systems.
>>
>> This series introduces a new MTD device driver that exposes such
>> firmware-managed storage as a standard MTD device in the Linux kernel.
>> The driver is built on top of the existing Qualcomm SCM infrastructure
>> and integrates with the MTD subsystem to provide a uniform interface to
>> userspace.
>>
>> This driver has been tested on Radxa Dragon Q6A, based on the Qualcomm
>> QCS6490 SoC, with a Winbond W25Q256JWPIQ SPI NOR flash device.
>>
>> Note that this platform previously used the standard Qualcomm Linux
>> firmware, which allowed direct access to the QSPI controller without
>> needing this driver. However, we plan to migrate to a Windows-compatible
>> firmware which is more feature-complete but restricts direct access.
>> Device tree changes for this transition will be sent separately.
>>
>> If kernel boots with EL2, access to the SCM storage will be denied. This
>> needs more investigation.
> So you plan to enable this driver only w/ the Gunyah based configuration
> and disable for the KVM one through the devicetree overlay ? I just
> don't want to break the KVM boot flow on other platforms supporting
> qcs6490.
On systems booted with EL2/KVM, the SCM storage GET_INFO call currently
returns -EINVAL. If a platform does not support SPI-NOR or SCM storage,
__qcom_scm_is_call_available() will cause the initialization to bail out
early.
There is no DT-based enable/disable mechanism, and this should not affect
KVM boot flow on other platforms.
Other QCS6490 LE platforms do not support SCM storage, as the LE firmware
does not support SPI-NOR boot. Radxa Dragon Q6A uses WP firmware and boots
from SPI-NOR.
The root cause of SCM storage being unavailable under EL2/KVM is still under
investigation.
[ 0.770124] qcom_scm: convention: smc arm 64
[ 0.775005] qcom_scm firmware:scm: qseecom: found qseecom with
version 0x1402000
[ 0.782990] qcom_scm firmware:scm: scm storage get info failed: -22
[ 0.999095] qcom_qseecom qcom_qseecom: setting up client for
qcom.tz.uefisecapp
Thanks for your reply.
Best regards,
Junhao Xie
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] mtd: devices: Qualcomm SCM storage support
2026-01-29 12:47 ` Junhao Xie
@ 2026-01-29 14:17 ` Konrad Dybcio
0 siblings, 0 replies; 20+ messages in thread
From: Konrad Dybcio @ 2026-01-29 14:17 UTC (permalink / raw)
To: Junhao Xie, Trilok Soni, Bjorn Andersson, Konrad Dybcio,
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra
Cc: linux-arm-msm, linux-kernel, linux-mtd, Xilin Wu
On 1/29/26 1:47 PM, Junhao Xie wrote:
> On 2026/1/29 5:43, Trilok Soni wrote:
>
>> On 1/26/2026 3:44 AM, Junhao Xie wrote:
>>> This patch series adds support for accessing storage devices managed by
>>> Qualcomm TrustZone firmware via SCM (Secure Channel Manager) by
>>> introducing a new MTD driver.
>>>
>>> On some Qualcomm platforms, firmware or BIOS-related storage (typically
>>> SPI NOR flash) is not directly accessible from the non-secure world.
>>> All read, write, and erase operations must be performed through SCM
>>> interfaces provided by the secure firmware. As a result, existing MTD
>>> SPI NOR drivers cannot be used directly on these systems.
>>>
>>> This series introduces a new MTD device driver that exposes such
>>> firmware-managed storage as a standard MTD device in the Linux kernel.
>>> The driver is built on top of the existing Qualcomm SCM infrastructure
>>> and integrates with the MTD subsystem to provide a uniform interface to
>>> userspace.
>>>
>>> This driver has been tested on Radxa Dragon Q6A, based on the Qualcomm
>>> QCS6490 SoC, with a Winbond W25Q256JWPIQ SPI NOR flash device.
>>>
>>> Note that this platform previously used the standard Qualcomm Linux
>>> firmware, which allowed direct access to the QSPI controller without
>>> needing this driver. However, we plan to migrate to a Windows-compatible
>>> firmware which is more feature-complete but restricts direct access.
>>> Device tree changes for this transition will be sent separately.
>>>
>>> If kernel boots with EL2, access to the SCM storage will be denied. This
>>> needs more investigation.
>> So you plan to enable this driver only w/ the Gunyah based configuration
>> and disable for the KVM one through the devicetree overlay ? I just
>> don't want to break the KVM boot flow on other platforms supporting
>> qcs6490.
>
> On systems booted with EL2/KVM, the SCM storage GET_INFO call currently
> returns -EINVAL. If a platform does not support SPI-NOR or SCM storage,
> __qcom_scm_is_call_available() will cause the initialization to bail out early.
>
> There is no DT-based enable/disable mechanism, and this should not affect
> KVM boot flow on other platforms.
>
> Other QCS6490 LE platforms do not support SCM storage, as the LE firmware
> does not support SPI-NOR boot. Radxa Dragon Q6A uses WP firmware and boots
> from SPI-NOR.
>
> The root cause of SCM storage being unavailable under EL2/KVM is still under
> investigation.
>
> [ 0.770124] qcom_scm: convention: smc arm 64
> [ 0.775005] qcom_scm firmware:scm: qseecom: found qseecom with version 0x1402000
> [ 0.782990] qcom_scm firmware:scm: scm storage get info failed: -22
> [ 0.999095] qcom_qseecom qcom_qseecom: setting up client for qcom.tz.uefisecapp
I think you need to create a shmbridge when running without gunyah, see
e.g.
4a7d6a78fbc6 ("firmware: qcom_scm: Add a prep version of auth_and_reset function")
where the memory is bridged right before the call. Without knowing any
better I would guesstimate you may need to qcom_tzalloc (which does that
under the hood) the 'struct qcom_scm_storage_info info' which you pass
to that func in qcom_scm_storage_init()
Konrad
^ permalink raw reply [flat|nested] 20+ messages in thread