linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] nvmem: stm32: add OP-TEE support for STM32MP13x
@ 2022-11-10 15:45 Patrick Delaunay
  2022-11-10 15:45 ` [PATCH v2 1/3] ARM: dts: stm32mp13: fix compatible for BSEC Patrick Delaunay
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Patrick Delaunay @ 2022-11-10 15:45 UTC (permalink / raw)
  To: Alexandre TORGUE, Rob Herring, Krzysztof Kozlowski,
	Maxime Coquelin, Srinivas Kandagatla
  Cc: Fabrice GASNIER, Patrick Delaunay, Etienne CARRIERE, devicetree,
	linux-arm-kernel, linux-kernel, linux-stm32


This serie update the NVMEM BSEC driver to be compatible with STM32MP13x
SoC and the trusted application STM32MP BSEC in OP-TEE

This serie solve issue in initial support of STM32MP131
(using BSEC STM32MP15 compatible) and so it break the STM32MP13x DTS
compatible.

I create this serie for more efficient review, including support for
STM32MP15x.

The first patches of the V1 series is already merged:
"dt-bindings: nvmem: add new stm32mp13 compatible for stm32-romem"

This STM32MP13x DTS break is acceptable as
- the STM32MP13x SoC is not yet available outside STMicroelectronics
  (not official)
- the same patch is already integrated or modifications are in progress in
  the other users (arm-trusted-firmware/TF-A, OP-TEE and U-Boot) of
  stm32mp131 device tree.

It is the good time to correct this issue before the real availability of
the SoC and before full support of STM32MP13x SoC in Linux kernel.

Regards

Patrick

Changes in v2:
- rebase series on linux-next/master
- minor update after V1 revue

Changes in v1:
- update commit message to indicate DTS break reason.

Patrick Delaunay (3):
  ARM: dts: stm32mp13: fix compatible for BSEC
  nvmem: stm32: add OP-TEE support for STM32MP13x
  nvmem: stm32: detect bsec pta presence for STM32MP15x

 arch/arm/boot/dts/stm32mp131.dtsi |   2 +-
 drivers/nvmem/stm32-romem.c       | 474 +++++++++++++++++++++++++++++-
 2 files changed, 471 insertions(+), 5 deletions(-)

-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v2 1/3] ARM: dts: stm32mp13: fix compatible for BSEC
  2022-11-10 15:45 [PATCH v2 0/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
@ 2022-11-10 15:45 ` Patrick Delaunay
  2022-11-10 15:45 ` [PATCH v2 2/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
  2022-11-10 15:45 ` [PATCH v2 3/3] nvmem: stm32: detect bsec pta presence for STM32MP15x Patrick Delaunay
  2 siblings, 0 replies; 6+ messages in thread
From: Patrick Delaunay @ 2022-11-10 15:45 UTC (permalink / raw)
  To: Alexandre TORGUE, Rob Herring, Krzysztof Kozlowski,
	Maxime Coquelin
  Cc: Fabrice GASNIER, Patrick Delaunay, devicetree, linux-arm-kernel,
	linux-kernel, linux-stm32

Use the correct compatible for stm32mp13 support.

The BSEC driver for STM32MP15x is not compatible with STM32MP13x. For
example the proprietary's smc STM32_SMC_BSEC is not supported in
STM32MP13x OP-TEE, it is replaced by SM32MP BSEC Pseudo Trusted
Application in OP-TEE to access to the secured IP BSEC on STM32MP13X SoC.

The correct compatible is already used in U-Boot and in upstream is in
progress for OP-TEE device tree.

As the SoC STM32MP13X is not yet official and it is not available
outside STMicroelectronics, it is the good time to break the DTS
compatibility and to correct the error done in the introduction of
STM32MP131.

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
---
This patch is already sent separately in:
https://lore.kernel.org/all/20221017134437.1.I167a5efc1f8777cce14518c6fa38400ac684de3e@changeid/
https://patchwork.kernel.org/project/linux-arm-kernel/list/?series=685815

I create a serie for more efficient review.

Patrick.

(no changes since v1)

Changes in v1:
- update commit message to indicate DTS break reason.

 arch/arm/boot/dts/stm32mp131.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/stm32mp131.dtsi b/arch/arm/boot/dts/stm32mp131.dtsi
index 2a9b3a5bba83..f034cbe0d5b2 100644
--- a/arch/arm/boot/dts/stm32mp131.dtsi
+++ b/arch/arm/boot/dts/stm32mp131.dtsi
@@ -522,7 +522,7 @@ rtc: rtc@5c004000 {
 		};
 
 		bsec: efuse@5c005000 {
-			compatible = "st,stm32mp15-bsec";
+			compatible = "st,stm32mp13-bsec";
 			reg = <0x5c005000 0x400>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v2 2/3] nvmem: stm32: add OP-TEE support for STM32MP13x
  2022-11-10 15:45 [PATCH v2 0/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
  2022-11-10 15:45 ` [PATCH v2 1/3] ARM: dts: stm32mp13: fix compatible for BSEC Patrick Delaunay
@ 2022-11-10 15:45 ` Patrick Delaunay
  2022-11-11 17:18   ` Srinivas Kandagatla
  2022-11-10 15:45 ` [PATCH v2 3/3] nvmem: stm32: detect bsec pta presence for STM32MP15x Patrick Delaunay
  2 siblings, 1 reply; 6+ messages in thread
From: Patrick Delaunay @ 2022-11-10 15:45 UTC (permalink / raw)
  To: Alexandre TORGUE, Srinivas Kandagatla, Maxime Coquelin
  Cc: Fabrice GASNIER, Patrick Delaunay, Etienne CARRIERE,
	linux-arm-kernel, linux-kernel, linux-stm32

For boot with OP-TEE on STM32MP13, the communication with the secure
world no more use STMicroelectronics SMC but communication with the
BSEC TA, for data access (read/write) or lock operation:
- all the request are sent to OP-TEE trusted application,
- for upper OTP with ECC protection and with word programming only
  each OTP are permanently locked when programmed to avoid ECC error
  on the second write operation

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
---

Changes in v2:
- rebase series on linux-next/master
- minor update after V1 revue
- add missing sentinel in stm32_romem_of_match()
- reorder function and remove prototypes for stm32_bsec_pta... functions
- change stm32_bsec_pta_find to static
- add return value in dev_err()
- cleanups some comments, which can be on one line
- remove test on priv->ctx in stm32_bsec_pta_remove
- add missing tee_shm_free(shm) in stm32_bsec_pta_write() when
  tee_shm_get_va failed
- return error in stm32_bsec_pta_find when devm_add_action_or_reset failed
- handle driver_register error in stm32_romem_init

 drivers/nvmem/stm32-romem.c | 445 +++++++++++++++++++++++++++++++++++-
 1 file changed, 441 insertions(+), 4 deletions(-)

diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index d1d03c2ad081..0a0e29d09b67 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/nvmem-provider.h>
 #include <linux/of_device.h>
+#include <linux/tee_drv.h>
 
 /* BSEC secure service access from non-secure */
 #define STM32_SMC_BSEC			0x82001003
@@ -25,14 +26,401 @@
 struct stm32_romem_cfg {
 	int size;
 	u8 lower;
+	bool ta;
 };
 
 struct stm32_romem_priv {
 	void __iomem *base;
 	struct nvmem_config cfg;
 	u8 lower;
+	struct device *ta;
 };
 
+#if IS_ENABLED(CONFIG_OPTEE)
+/*
+ * Read OTP memory
+ *
+ * [in]		value[0].a		OTP start offset in byte
+ * [in]		value[0].b		Access type (0:shadow, 1:fuse, 2:lock)
+ * [out]	memref[1].buffer	Output buffer to store read values
+ * [out]	memref[1].size		Size of OTP to be read
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ */
+#define PTA_BSEC_READ_MEM		0x0 /* Read OTP */
+
+/*
+ * Write OTP memory
+ *
+ * [in]		value[0].a		OTP start offset in byte
+ * [in]		value[0].b		Access type (0:shadow, 1:fuse, 2:lock)
+ * [in]		memref[1].buffer	Input buffer to read values
+ * [in]		memref[1].size		Size of OTP to be written
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ */
+#define PTA_BSEC_WRITE_MEM		0x1	/* Write OTP */
+
+/* value of PTA_BSEC access type = value[in] b */
+#define SHADOW_ACCESS	0
+#define FUSE_ACCESS	1
+#define LOCK_ACCESS	2
+
+/* Bitfield definition for LOCK status */
+#define LOCK_PERM			BIT(30)
+
+/**
+ * struct stm32_bsec_pta_priv - OP-TEE BSEC TA private data
+ * @ctx:		OP-TEE context handler.
+ * @session_id:		TA session identifier.
+ */
+struct stm32_bsec_pta_priv {
+	struct tee_context *ctx;
+	u32 session_id;
+};
+
+/*
+ * Check whether this driver supports the BSEC TA in the TEE instance
+ * represented by the params (ver/data) to this function.
+ */
+static int stm32_bsec_pta_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+	/* Currently this driver only supports GP compliant, OP-TEE based TA */
+	if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
+		(ver->gen_caps & TEE_GEN_CAP_GP))
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * stm32_bsec_pta_probe() - initialize the PTA BSEC
+ * @dev: the platform_device description.
+ *
+ * Return:
+ *	On success, 0. On failure, -errno.
+ */
+static int stm32_bsec_pta_probe(struct device *dev)
+{
+	int rc;
+	struct tee_ioctl_open_session_arg sess_arg;
+	struct tee_client_device *tee_device = to_tee_client_device(dev);
+	struct stm32_bsec_pta_priv *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/* Open context with TEE driver */
+	priv->ctx = tee_client_open_context(NULL, stm32_bsec_pta_match, NULL, NULL);
+	if (IS_ERR(priv->ctx)) {
+		rc = PTR_ERR(priv->ctx);
+		if (rc == -ENOENT)
+			return -EPROBE_DEFER;
+		dev_err(dev, "%s: tee_client_open_context failed (%d)\n", __func__, rc);
+
+		return rc;
+	}
+
+	/* Open a session with BSEC TA */
+	memset(&sess_arg, 0, sizeof(sess_arg));
+	export_uuid(sess_arg.uuid, &tee_device->id.uuid);
+	sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+	sess_arg.num_params = 0;
+
+	rc = tee_client_open_session(priv->ctx, &sess_arg, NULL);
+	if ((rc < 0) || (sess_arg.ret != 0)) {
+		dev_err(dev, "%s: tee_client_open_session failed err:%x, ret:%x\n",
+			__func__, sess_arg.ret, rc);
+		rc = -EINVAL;
+		goto out_tee_session;
+	}
+	priv->session_id = sess_arg.session;
+	dev_set_drvdata(dev, priv);
+
+	return 0;
+
+out_tee_session:
+	tee_client_close_context(priv->ctx);
+
+	return rc;
+}
+
+/**
+ * stm32_bsec_pta_remove() - remove the BSEC TEE device
+ * @dev: the platform_device description.
+ *
+ * Return:
+ *	0 always.
+ */
+static int stm32_bsec_pta_remove(struct device *dev)
+{
+	struct stm32_bsec_pta_priv *priv = dev_get_drvdata(dev);
+
+	tee_client_close_session(priv->ctx, priv->session_id);
+	tee_client_close_context(priv->ctx);
+
+	return 0;
+}
+
+/**
+ * stm32_bsec_pta_read() - nvmem read access using PTA client driver
+ * @context: nvmem context => romem privdate data
+ * @offset: nvmem offset
+ * @buf: buffer to fill with nvem values
+ * @bytes: number of bytes to read
+ *
+ * Return:
+ *	On success, 0. On failure, -errno.
+ */
+static int stm32_bsec_pta_read(void *context, unsigned int offset, void *buf,
+			       size_t bytes)
+{
+	struct stm32_romem_priv *romem_priv = context;
+	struct device *dev;
+	struct stm32_bsec_pta_priv *priv;
+	struct tee_shm *shm;
+	struct tee_ioctl_invoke_arg arg;
+	struct tee_param param[2];
+	u8 *shm_buf;
+	u32 start, num_bytes;
+	int ret;
+
+	dev = romem_priv->ta;
+	if (!dev) {
+		pr_err("TA_BSEC invoke without driver\n");
+		return -ENXIO;
+	}
+
+	priv = dev_get_drvdata(dev);
+
+	memset(&arg, 0, sizeof(arg));
+	memset(&param, 0, sizeof(param));
+
+	arg.func = PTA_BSEC_READ_MEM;
+	arg.session = priv->session_id;
+	arg.num_params = 2;
+
+	/* align access on 32bits */
+	start = ALIGN_DOWN(offset, 4);
+	num_bytes = round_up(offset + bytes - start, 4);
+	param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+	param[0].u.value.a = start;
+	param[0].u.value.b = SHADOW_ACCESS;
+
+	shm = tee_shm_alloc_kernel_buf(priv->ctx, num_bytes);
+	if (IS_ERR(shm))
+		return PTR_ERR(shm);
+
+	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+	param[1].u.memref.shm = shm;
+	param[1].u.memref.size = num_bytes;
+
+	ret = tee_client_invoke_func(priv->ctx, &arg, param);
+	if (ret < 0 || arg.ret != 0) {
+		dev_err(dev, "TA_BSEC invoke failed TEE err:%x, ret:%x\n",
+			arg.ret, ret);
+		if (!ret)
+			ret = -EIO;
+	}
+	if (!ret) {
+		shm_buf = tee_shm_get_va(shm, 0);
+		if (IS_ERR(shm_buf)) {
+			ret = PTR_ERR(shm_buf);
+			dev_err(dev, "tee_shm_get_va failed for transmit (%d)\n", ret);
+		} else {
+			/* read data from 32 bits aligned buffer */
+			memcpy(buf, &shm_buf[offset % 4], bytes);
+		}
+	}
+
+	tee_shm_free(shm);
+
+	return ret;
+}
+
+/**
+ * stm32_bsec_pta_write() - nvmem write access using PTA client driver
+ * @context: nvmem context => romem privdate data
+ * @offset: nvmem offset
+ * @buf: buffer with nvem values
+ * @bytes: number of bytes to write
+ *
+ * Return:
+ *	On success, 0. On failure, -errno.
+ */
+static int stm32_bsec_pta_write(void *context, unsigned int offset, void *buf,
+				size_t bytes)
+{
+	struct stm32_romem_priv *romem_priv = context;
+	struct device *dev;
+	struct stm32_bsec_pta_priv *priv;
+	struct tee_shm *shm;
+	struct tee_ioctl_invoke_arg arg;
+	struct tee_param param[2];
+	u8 *shm_buf;
+	int ret;
+
+	dev = romem_priv->ta;
+	if (!dev) {
+		pr_err("TA_BSEC invoke without driver\n");
+		return -ENXIO;
+	}
+
+	/* Allow only writing complete 32-bits aligned words */
+	if ((bytes % 4) || (offset % 4))
+		return -EINVAL;
+
+	priv = dev_get_drvdata(dev);
+
+	memset(&arg, 0, sizeof(arg));
+	memset(&param, 0, sizeof(param));
+
+	arg.func = PTA_BSEC_WRITE_MEM;
+	arg.session = priv->session_id;
+	arg.num_params = 2;
+
+	param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+	param[0].u.value.a = offset;
+	param[0].u.value.b = FUSE_ACCESS;
+
+	shm = tee_shm_alloc_kernel_buf(priv->ctx, bytes);
+	if (IS_ERR(shm))
+		return PTR_ERR(shm);
+
+	param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	param[1].u.memref.shm = shm;
+	param[1].u.memref.size = bytes;
+
+	shm_buf = tee_shm_get_va(shm, 0);
+	if (IS_ERR(shm_buf)) {
+		ret = PTR_ERR(shm_buf);
+		dev_err(dev, "tee_shm_get_va failed for transmit (%d)\n", ret);
+		tee_shm_free(shm);
+
+		return ret;
+	}
+
+	memcpy(shm_buf, buf, bytes);
+
+	ret = tee_client_invoke_func(priv->ctx, &arg, param);
+	if (ret < 0 || arg.ret != 0) {
+		dev_err(dev, "TA_BSEC invoke failed TEE err:%x, ret:%x\n",
+			arg.ret, ret);
+		if (!ret)
+			ret = -EIO;
+	}
+	dev_dbg(dev, "Write OTPs %d to %d, ret=%d\n",
+		offset / 4, (offset + bytes) / 4, ret);
+
+	/* Lock the upper OTPs with ECC protection, word programming only */
+	if (!ret && ((offset + bytes) >= (romem_priv->lower * 4))) {
+		u32 start, nb_lock;
+		u32 *lock = (u32 *)shm_buf;
+		int i;
+
+		/*
+		 * don't lock the lower OTPs, no ECC protection and incremental
+		 * bit programming, a second write is allowed
+		 */
+		start = max_t(u32, offset, romem_priv->lower * 4);
+		nb_lock = (offset + bytes - start) / 4;
+
+		param[0].u.value.a = start;
+		param[0].u.value.b = LOCK_ACCESS;
+		param[1].u.memref.size = nb_lock * 4;
+
+		for (i = 0; i < nb_lock; i++)
+			lock[i] = LOCK_PERM;
+
+		ret = tee_client_invoke_func(priv->ctx, &arg, param);
+		if (ret < 0 || arg.ret != 0) {
+			dev_err(dev, "TA_BSEC invoke failed TEE err:%x, ret:%x\n",
+				arg.ret, ret);
+			if (!ret)
+				ret = -EIO;
+		}
+		dev_dbg(dev, "Lock upper OTPs %d to %d, ret=%d\n",
+			start / 4, start / 4 + nb_lock, ret);
+	}
+
+	tee_shm_free(shm);
+
+	return ret;
+}
+
+static const struct tee_client_device_id stm32_bsec_id_table[] = {
+	{
+		UUID_INIT(0x94cf71ad, 0x80e6, 0x40b5,
+			  0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03)
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(tee, stm32_bsec_id_table);
+
+static struct tee_client_driver stm32_bsec_pta_driver = {
+	.id_table	= stm32_bsec_id_table,
+	.driver		= {
+		.name = "stm32-bsec-pta",
+		.bus = &tee_bus_type,
+		.probe = stm32_bsec_pta_probe,
+		.remove = stm32_bsec_pta_remove,
+	},
+};
+
+static void stm32_bsec_put_device(void *data)
+{
+	put_device(data);
+}
+
+static struct device *stm32_bsec_pta_find(struct device *dev)
+{
+	struct device *pta_dev;
+	int ret;
+
+	pta_dev = driver_find_next_device(&stm32_bsec_pta_driver.driver, NULL);
+
+	if (pta_dev) {
+		ret = devm_add_action_or_reset(dev, stm32_bsec_put_device, pta_dev);
+		if (ret)
+			dev_err(dev, "devm_add_action_or_reset() failed (%d)\n", ret);
+
+		return ERR_PTR(ret);
+	}
+
+	return pta_dev;
+}
+
+#else
+static int stm32_bsec_pta_read(void *context, unsigned int offset, void *buf,
+			       size_t bytes)
+{
+	pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
+
+	return -ENXIO;
+}
+
+static int stm32_bsec_pta_write(void *context, unsigned int offset, void *buf,
+				size_t bytes)
+{
+	pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
+
+	return -ENXIO;
+}
+
+static struct device *stm32_bsec_pta_find(struct device *dev)
+{
+	pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
+
+	return NULL;
+}
+#endif
+
 static int stm32_romem_read(void *context, unsigned int offset, void *buf,
 			    size_t bytes)
 {
@@ -173,15 +561,27 @@ static int stm32_romem_probe(struct platform_device *pdev)
 	} else {
 		priv->cfg.size = cfg->size;
 		priv->lower = cfg->lower;
-		priv->cfg.reg_read = stm32_bsec_read;
-		priv->cfg.reg_write = stm32_bsec_write;
+		if (cfg->ta) {
+			priv->ta = stm32_bsec_pta_find(dev);
+			/* wait for OP-TEE client driver to be up and ready */
+			if (!priv->ta)
+				return -EPROBE_DEFER;
+			if (IS_ERR(priv->ta))
+				return PTR_ERR(priv->ta);
+
+			priv->cfg.reg_read = stm32_bsec_pta_read;
+			priv->cfg.reg_write = stm32_bsec_pta_write;
+		} else {
+			priv->cfg.reg_read = stm32_bsec_read;
+			priv->cfg.reg_write = stm32_bsec_write;
+		}
 	}
 
 	return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg));
 }
 
 /*
- * STM32MP15 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
+ * STM32MP15/13 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
  * => 96 x 32-bits data words
  * - Lower: 1K bits, 2:1 redundancy, incremental bit programming
  *   => 32 (x 32-bits) lower shadow registers = words 0 to 31
@@ -191,6 +591,13 @@ static int stm32_romem_probe(struct platform_device *pdev)
 static const struct stm32_romem_cfg stm32mp15_bsec_cfg = {
 	.size = 384,
 	.lower = 32,
+	.ta = false,
+};
+
+static const struct stm32_romem_cfg stm32mp13_bsec_cfg = {
+	.size = 384,
+	.lower = 32,
+	.ta = true,
 };
 
 static const struct of_device_id stm32_romem_of_match[] = {
@@ -198,7 +605,10 @@ static const struct of_device_id stm32_romem_of_match[] = {
 		.compatible = "st,stm32mp15-bsec",
 		.data = (void *)&stm32mp15_bsec_cfg,
 	}, {
+		.compatible = "st,stm32mp13-bsec",
+		.data = (void *)&stm32mp13_bsec_cfg,
 	},
+	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, stm32_romem_of_match);
 
@@ -209,7 +619,34 @@ static struct platform_driver stm32_romem_driver = {
 		.of_match_table = of_match_ptr(stm32_romem_of_match),
 	},
 };
-module_platform_driver(stm32_romem_driver);
+
+static int __init stm32_romem_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&stm32_romem_driver);
+	if (rc)
+		return rc;
+
+#if IS_ENABLED(CONFIG_OPTEE)
+	rc = driver_register(&stm32_bsec_pta_driver.driver);
+	if (rc)
+		platform_driver_unregister(&stm32_romem_driver);
+#endif
+
+	return rc;
+}
+
+static void __exit stm32_romem_exit(void)
+{
+	platform_driver_unregister(&stm32_romem_driver);
+#if IS_ENABLED(CONFIG_OPTEE)
+	driver_unregister(&stm32_bsec_pta_driver.driver);
+#endif
+}
+
+module_init(stm32_romem_init);
+module_exit(stm32_romem_exit);
 
 MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics STM32 RO-MEM");
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v2 3/3] nvmem: stm32: detect bsec pta presence for STM32MP15x
  2022-11-10 15:45 [PATCH v2 0/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
  2022-11-10 15:45 ` [PATCH v2 1/3] ARM: dts: stm32mp13: fix compatible for BSEC Patrick Delaunay
  2022-11-10 15:45 ` [PATCH v2 2/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
@ 2022-11-10 15:45 ` Patrick Delaunay
  2 siblings, 0 replies; 6+ messages in thread
From: Patrick Delaunay @ 2022-11-10 15:45 UTC (permalink / raw)
  To: Alexandre TORGUE, Srinivas Kandagatla, Maxime Coquelin
  Cc: Fabrice GASNIER, Patrick Delaunay, linux-arm-kernel, linux-kernel,
	linux-stm32

On STM32MP15x SoC, the SMC backend is optional when OP-TEE is used;
the PTA BSEC should be used as it is done on STM32MP13x platform,
but the BSEC SMC can be also used: it is a legacy mode in OP-TEE,
not recommended but used in previous OP-TEE firmware.

The presence of OP-TEE is dynamically detected in STM32MP15x device tree
and the supported NVMEM backend is dynamically detected:
- PTA with stm32_bsec_pta_find
- SMC with stm32_bsec_check

With OP-TEE but without PTA and SMC detection, the probe is deferred for
STM32MP15x devices.

On STM32MP13x platform, only the PTA is supported with cfg->ta = true
and this detection is skipped.

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
---

Changes in v2:
- Added patch in the serie for BSEC PTA support on STM32MP15x
  with dynamic detection of OP-TEE presence and SMC support (legacy mode)

 drivers/nvmem/stm32-romem.c | 37 +++++++++++++++++++++++++++++++++----
 1 file changed, 33 insertions(+), 4 deletions(-)

diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index 0a0e29d09b67..35997d581c9d 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -526,6 +526,31 @@ static int stm32_bsec_write(void *context, unsigned int offset, void *buf,
 	return 0;
 }
 
+static bool stm32_bsec_smc_check(void)
+{
+	u32 val;
+	int ret;
+
+	/* check that the OP-TEE support the BSEC SMC (legacy mode) */
+	ret = stm32_bsec_smc(STM32_SMC_READ_SHADOW, 0, 0, &val);
+
+	return !ret;
+}
+
+static bool optee_presence_check(void)
+{
+	struct device_node *np;
+	bool tee_detected = false;
+
+	/* check that the OP-TEE node is present and available. */
+	np = of_find_node_by_path("/firmware/optee");
+	if (np && of_device_is_available(np))
+		tee_detected = true;
+	of_node_put(np);
+
+	return tee_detected;
+}
+
 static int stm32_romem_probe(struct platform_device *pdev)
 {
 	const struct stm32_romem_cfg *cfg;
@@ -561,14 +586,18 @@ static int stm32_romem_probe(struct platform_device *pdev)
 	} else {
 		priv->cfg.size = cfg->size;
 		priv->lower = cfg->lower;
-		if (cfg->ta) {
+		if (cfg->ta || optee_presence_check()) {
 			priv->ta = stm32_bsec_pta_find(dev);
 			/* wait for OP-TEE client driver to be up and ready */
-			if (!priv->ta)
-				return -EPROBE_DEFER;
+			if (!priv->ta) {
+				/* BSEC PTA is required or SMC not ready */
+				if (cfg->ta || !stm32_bsec_smc_check())
+					return -EPROBE_DEFER;
+			}
 			if (IS_ERR(priv->ta))
 				return PTR_ERR(priv->ta);
-
+		}
+		if (priv->ta) {
 			priv->cfg.reg_read = stm32_bsec_pta_read;
 			priv->cfg.reg_write = stm32_bsec_pta_write;
 		} else {
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 2/3] nvmem: stm32: add OP-TEE support for STM32MP13x
  2022-11-10 15:45 ` [PATCH v2 2/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
@ 2022-11-11 17:18   ` Srinivas Kandagatla
  2022-11-14 14:20     ` Patrick DELAUNAY
  0 siblings, 1 reply; 6+ messages in thread
From: Srinivas Kandagatla @ 2022-11-11 17:18 UTC (permalink / raw)
  To: Patrick Delaunay, Alexandre TORGUE, Maxime Coquelin
  Cc: Fabrice GASNIER, Etienne CARRIERE, linux-arm-kernel, linux-kernel,
	linux-stm32



On 10/11/2022 15:45, Patrick Delaunay wrote:
> For boot with OP-TEE on STM32MP13, the communication with the secure
> world no more use STMicroelectronics SMC but communication with the
> BSEC TA, for data access (read/write) or lock operation:
> - all the request are sent to OP-TEE trusted application,
> - for upper OTP with ECC protection and with word programming only
>    each OTP are permanently locked when programmed to avoid ECC error
>    on the second write operation
> 
> Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> ---
> 
> Changes in v2:
> - rebase series on linux-next/master
> - minor update after V1 revue
> - add missing sentinel in stm32_romem_of_match()
> - reorder function and remove prototypes for stm32_bsec_pta... functions
> - change stm32_bsec_pta_find to static
> - add return value in dev_err()
> - cleanups some comments, which can be on one line
> - remove test on priv->ctx in stm32_bsec_pta_remove
> - add missing tee_shm_free(shm) in stm32_bsec_pta_write() when
>    tee_shm_get_va failed
> - return error in stm32_bsec_pta_find when devm_add_action_or_reset failed
> - handle driver_register error in stm32_romem_init
> 
>   drivers/nvmem/stm32-romem.c | 445 +++++++++++++++++++++++++++++++++++-
>   1 file changed, 441 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
> index d1d03c2ad081..0a0e29d09b67 100644
> --- a/drivers/nvmem/stm32-romem.c
> +++ b/drivers/nvmem/stm32-romem.c
> @@ -11,6 +11,7 @@
>   #include <linux/module.h>
>   #include <linux/nvmem-provider.h>
>   #include <linux/of_device.h>
> +#include <linux/tee_drv.h>
>   
>   /* BSEC secure service access from non-secure */
>   #define STM32_SMC_BSEC			0x82001003
> @@ -25,14 +26,401 @@
>   struct stm32_romem_cfg {
>   	int size;
>   	u8 lower;
> +	bool ta;
>   };
>   
>   struct stm32_romem_priv {
>   	void __iomem *base;
>   	struct nvmem_config cfg;
>   	u8 lower;
> +	struct device *ta;
>   };
>   
> +#if IS_ENABLED(CONFIG_OPTEE)
> +/*

...

> +
> +static const struct tee_client_device_id stm32_bsec_id_table[] = {
> +	{
> +		UUID_INIT(0x94cf71ad, 0x80e6, 0x40b5,
> +			  0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03)
> +	},
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(tee, stm32_bsec_id_table);
> +
> +static struct tee_client_driver stm32_bsec_pta_driver = {
> +	.id_table	= stm32_bsec_id_table,
> +	.driver		= {
> +		.name = "stm32-bsec-pta",
> +		.bus = &tee_bus_type,
> +		.probe = stm32_bsec_pta_probe,
> +		.remove = stm32_bsec_pta_remove,
> +	},
> +};
> +
> +static void stm32_bsec_put_device(void *data)
> +{
> +	put_device(data);
> +}
> +
> +static struct device *stm32_bsec_pta_find(struct device *dev)
> +{
> +	struct device *pta_dev;
> +	int ret;
> +
> +	pta_dev = driver_find_next_device(&stm32_bsec_pta_driver.driver, NULL);

This is clearly not representing the dependencies in a proper device model.


If the nvmem provider is a TEE client driver lets model it that way.. 
brining in a additional device and somehow trying to link it with TEE 
driver is  a hack.


> +
> +	if (pta_dev) {
> +		ret = devm_add_action_or_reset(dev, stm32_bsec_put_device, pta_dev);
> +		if (ret)
> +			dev_err(dev, "devm_add_action_or_reset() failed (%d)\n", ret);
> +
> +		return ERR_PTR(ret);
> +	}
> +
> +	return pta_dev;
> +}
> +
> +#else
> +static int stm32_bsec_pta_read(void *context, unsigned int offset, void *buf,
> +			       size_t bytes)
> +{
> +	pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
> +
> +	return -ENXIO;
> +}
> +
> +static int stm32_bsec_pta_write(void *context, unsigned int offset, void *buf,
> +				size_t bytes)
> +{
> +	pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
> +
> +	return -ENXIO;
> +}
> +
> +static struct device *stm32_bsec_pta_find(struct device *dev)
> +{
> +	pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
> +
> +	return NULL;
> +}
> +#endif

ifdefing inside the drvier is really ugly, please move this libary 
functions to a seperate file and add dependecy properly in Kconfig.

> +
>   static int stm32_romem_read(void *context, unsigned int offset, void *buf,
>   			    size_t bytes)
>   {
> @@ -173,15 +561,27 @@ static int stm32_romem_probe(struct platform_device *pdev)
>   	} else {
>   		priv->cfg.size = cfg->size;
>   		priv->lower = cfg->lower;
> -		priv->cfg.reg_read = stm32_bsec_read;
> -		priv->cfg.reg_write = stm32_bsec_write;
> +		if (cfg->ta) {
> +			priv->ta = stm32_bsec_pta_find(dev);
> +			/* wait for OP-TEE client driver to be up and ready */
> +			if (!priv->ta)
> +				return -EPROBE_DEFER;
> +			if (IS_ERR(priv->ta))
> +				return PTR_ERR(priv->ta);
> +
> +			priv->cfg.reg_read = stm32_bsec_pta_read;
> +			priv->cfg.reg_write = stm32_bsec_pta_write;
> +		} else {
> +			priv->cfg.reg_read = stm32_bsec_read;
> +			priv->cfg.reg_write = stm32_bsec_write;
> +		}
>   	}
>   
>   	return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg));
>   }
>   
>   /*
> - * STM32MP15 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
> + * STM32MP15/13 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
>    * => 96 x 32-bits data words
>    * - Lower: 1K bits, 2:1 redundancy, incremental bit programming
>    *   => 32 (x 32-bits) lower shadow registers = words 0 to 31
> @@ -191,6 +591,13 @@ static int stm32_romem_probe(struct platform_device *pdev)
>   static const struct stm32_romem_cfg stm32mp15_bsec_cfg = {
>   	.size = 384,
>   	.lower = 32,
> +	.ta = false,
> +};
> +
> +static const struct stm32_romem_cfg stm32mp13_bsec_cfg = {
> +	.size = 384,
> +	.lower = 32,
> +	.ta = true,
>   };
>   
>   static const struct of_device_id stm32_romem_of_match[] = {
> @@ -198,7 +605,10 @@ static const struct of_device_id stm32_romem_of_match[] = {
>   		.compatible = "st,stm32mp15-bsec",
>   		.data = (void *)&stm32mp15_bsec_cfg,
>   	}, {
> +		.compatible = "st,stm32mp13-bsec",
> +		.data = (void *)&stm32mp13_bsec_cfg,
>   	},
> +	{ /* sentinel */ },
>   };
>   MODULE_DEVICE_TABLE(of, stm32_romem_of_match);
>   
> @@ -209,7 +619,34 @@ static struct platform_driver stm32_romem_driver = {
>   		.of_match_table = of_match_ptr(stm32_romem_of_match),
>   	},
>   };
> -module_platform_driver(stm32_romem_driver);
> +
> +static int __init stm32_romem_init(void)
> +{
> +	int rc;
> +
> +	rc = platform_driver_register(&stm32_romem_driver);
> +	if (rc)
> +		return rc;
> +
> +#if IS_ENABLED(CONFIG_OPTEE)
> +	rc = driver_register(&stm32_bsec_pta_driver.driver);
> +	if (rc)
> +		platform_driver_unregister(&stm32_romem_driver);
> +#endif
> +
> +	return rc;
> +}
> +
> +static void __exit stm32_romem_exit(void)
> +{
> +	platform_driver_unregister(&stm32_romem_driver);
> +#if IS_ENABLED(CONFIG_OPTEE)
> +	driver_unregister(&stm32_bsec_pta_driver.driver);
> +#endif
> +}
> +
> +module_init(stm32_romem_init);
> +module_exit(stm32_romem_exit);
>   
>   MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
>   MODULE_DESCRIPTION("STMicroelectronics STM32 RO-MEM");

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 2/3] nvmem: stm32: add OP-TEE support for STM32MP13x
  2022-11-11 17:18   ` Srinivas Kandagatla
@ 2022-11-14 14:20     ` Patrick DELAUNAY
  0 siblings, 0 replies; 6+ messages in thread
From: Patrick DELAUNAY @ 2022-11-14 14:20 UTC (permalink / raw)
  To: Srinivas Kandagatla, Alexandre TORGUE, Maxime Coquelin
  Cc: Fabrice GASNIER, Etienne CARRIERE, linux-arm-kernel, linux-kernel,
	linux-stm32

Hi,

On 11/11/22 18:18, Srinivas Kandagatla wrote:
>
>
> On 10/11/2022 15:45, Patrick Delaunay wrote:
>> For boot with OP-TEE on STM32MP13, the communication with the secure
>> world no more use STMicroelectronics SMC but communication with the
>> BSEC TA, for data access (read/write) or lock operation:
>> - all the request are sent to OP-TEE trusted application,
>> - for upper OTP with ECC protection and with word programming only
>>    each OTP are permanently locked when programmed to avoid ECC error
>>    on the second write operation
>>
>> Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
>> ---
>>
>> Changes in v2:
>> - rebase series on linux-next/master
>> - minor update after V1 revue
>> - add missing sentinel in stm32_romem_of_match()
>> - reorder function and remove prototypes for stm32_bsec_pta... functions
>> - change stm32_bsec_pta_find to static
>> - add return value in dev_err()
>> - cleanups some comments, which can be on one line
>> - remove test on priv->ctx in stm32_bsec_pta_remove
>> - add missing tee_shm_free(shm) in stm32_bsec_pta_write() when
>>    tee_shm_get_va failed
>> - return error in stm32_bsec_pta_find when devm_add_action_or_reset 
>> failed
>> - handle driver_register error in stm32_romem_init
>>
>>   drivers/nvmem/stm32-romem.c | 445 +++++++++++++++++++++++++++++++++++-
>>   1 file changed, 441 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
>> index d1d03c2ad081..0a0e29d09b67 100644
>> --- a/drivers/nvmem/stm32-romem.c
>> +++ b/drivers/nvmem/stm32-romem.c
>> @@ -11,6 +11,7 @@
>>   #include <linux/module.h>
>>   #include <linux/nvmem-provider.h>
>>   #include <linux/of_device.h>
>> +#include <linux/tee_drv.h>
>>     /* BSEC secure service access from non-secure */
>>   #define STM32_SMC_BSEC            0x82001003
>> @@ -25,14 +26,401 @@
>>   struct stm32_romem_cfg {
>>       int size;
>>       u8 lower;
>> +    bool ta;
>>   };
>>     struct stm32_romem_priv {
>>       void __iomem *base;
>>       struct nvmem_config cfg;
>>       u8 lower;
>> +    struct device *ta;
>>   };
>>   +#if IS_ENABLED(CONFIG_OPTEE)
>> +/*
>
> ...
>
>> +
>> +static const struct tee_client_device_id stm32_bsec_id_table[] = {
>> +    {
>> +        UUID_INIT(0x94cf71ad, 0x80e6, 0x40b5,
>> +              0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03)
>> +    },
>> +    { }
>> +};
>> +
>> +MODULE_DEVICE_TABLE(tee, stm32_bsec_id_table);
>> +
>> +static struct tee_client_driver stm32_bsec_pta_driver = {
>> +    .id_table    = stm32_bsec_id_table,
>> +    .driver        = {
>> +        .name = "stm32-bsec-pta",
>> +        .bus = &tee_bus_type,
>> +        .probe = stm32_bsec_pta_probe,
>> +        .remove = stm32_bsec_pta_remove,
>> +    },
>> +};
>> +
>> +static void stm32_bsec_put_device(void *data)
>> +{
>> +    put_device(data);
>> +}
>> +
>> +static struct device *stm32_bsec_pta_find(struct device *dev)
>> +{
>> +    struct device *pta_dev;
>> +    int ret;
>> +
>> +    pta_dev = driver_find_next_device(&stm32_bsec_pta_driver.driver, 
>> NULL);
>
> This is clearly not representing the dependencies in a proper device 
> model.
>
>
> If the nvmem provider is a TEE client driver lets model it that way.. 
> brining in a additional device and somehow trying to link it with TEE 
> driver is  a hack.
>

TEE is a firmware which allow access to secure ressource... including 
BSEC ressources


I think it is also the case on a other driver = mson_sm.c

=> econfig->priv = fw;

       fw is a handle to the firmware (secure monitor) which provide 
access to secure ressource



BSEC is a hardware device on the bus,

it it describe in the device tree, with a compatible,

the same description should be used for any SW, not only Linux kernel.

and the nvmem cell description are sub-node of BSEC node, used as 
phandle by other device.


I need to have a link between the NVMEM driver and the OP-TEE session;

But I use the tee bus discovery here it is a error,

because that create a second uneeded driver "stm32_bsec_pta_driver"...


I will remove this part, and only kept the PTA request with new lib 
functions "stm32_bsec_pta_XXX()".



>
>> +
>> +    if (pta_dev) {
>> +        ret = devm_add_action_or_reset(dev, stm32_bsec_put_device, 
>> pta_dev);
>> +        if (ret)
>> +            dev_err(dev, "devm_add_action_or_reset() failed (%d)\n", 
>> ret);
>> +
>> +        return ERR_PTR(ret);
>> +    }
>> +
>> +    return pta_dev;
>> +}
>> +
>> +#else
>> +static int stm32_bsec_pta_read(void *context, unsigned int offset, 
>> void *buf,
>> +                   size_t bytes)
>> +{
>> +    pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
>> +
>> +    return -ENXIO;
>> +}
>> +
>> +static int stm32_bsec_pta_write(void *context, unsigned int offset, 
>> void *buf,
>> +                size_t bytes)
>> +{
>> +    pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
>> +
>> +    return -ENXIO;
>> +}
>> +
>> +static struct device *stm32_bsec_pta_find(struct device *dev)
>> +{
>> +    pr_debug("%s: TA BSEC request without OPTEE support\n", __func__);
>> +
>> +    return NULL;
>> +}
>> +#endif
>
> ifdefing inside the drvier is really ugly, please move this libary 
> functions to a seperate file and add dependecy properly in Kconfig.


Ok

regards


Patrick


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2022-11-14 14:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-10 15:45 [PATCH v2 0/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
2022-11-10 15:45 ` [PATCH v2 1/3] ARM: dts: stm32mp13: fix compatible for BSEC Patrick Delaunay
2022-11-10 15:45 ` [PATCH v2 2/3] nvmem: stm32: add OP-TEE support for STM32MP13x Patrick Delaunay
2022-11-11 17:18   ` Srinivas Kandagatla
2022-11-14 14:20     ` Patrick DELAUNAY
2022-11-10 15:45 ` [PATCH v2 3/3] nvmem: stm32: detect bsec pta presence for STM32MP15x Patrick Delaunay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).