[RFC WIP PATCH v2] Load VDEC FW from TEE

Marc Gonzalez mgonzalez at freebox.fr
Tue Feb 27 06:25:56 PST 2024


Preliminary support for loading VDEC FW through TEE.

TODO:
- split the patch in 2 (or more?)
  - DT binding amlogic,tee-loads-vdec-fw
  - driver code
- test how long the delays need to be (after load & after start)
- add the DT prop to arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am.dts


---
 Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml |  4 ++++
 drivers/staging/media/meson/vdec/Makefile                    |  1 +
 drivers/staging/media/meson/vdec/optee.c                     | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/staging/media/meson/vdec/optee.h                     |  5 +++++
 drivers/staging/media/meson/vdec/vdec.c                      |  3 +++
 drivers/staging/media/meson/vdec/vdec.h                      |  2 ++
 drivers/staging/media/meson/vdec/vdec_1.c                    | 14 +++++++++++++-
 drivers/staging/media/meson/vdec/vdec_hevc.c                 |  9 ++++++++-
 8 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml b/Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
index 55930f6107c9c..543a90e83bfdc 100644
--- a/Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
+++ b/Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
@@ -82,6 +82,10 @@ properties:
     description: should point to a canvas provider node
     $ref: /schemas/types.yaml#/definitions/phandle
 
+  amlogic,tee-loads-vdec-fw:
+    type: boolean
+    description: Linux must request FW load from TEE
+
 allOf:
   - if:
       properties:
diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile
index 6e726af84ac9b..41e5006fa6294 100644
--- a/drivers/staging/media/meson/vdec/Makefile
+++ b/drivers/staging/media/meson/vdec/Makefile
@@ -4,5 +4,6 @@
 meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
 meson-vdec-objs += vdec_1.o vdec_hevc.o
 meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_hevc_common.o codec_vp9.o
+meson-vdec-objs += optee.o
 
 obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
diff --git a/drivers/staging/media/meson/vdec/optee.c b/drivers/staging/media/meson/vdec/optee.c
new file mode 100644
index 0000000000000..00ea935f7656a
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/optee.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2024 Freebox SAS
+
+#include "optee.h"
+#include <linux/arm-smccc.h>
+
+#define TEE_SMC_FAST_CALL_VAL(func_num) \
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, ARM_SMCCC_OWNER_TRUSTED_OS, func_num)
+
+static void request_fw_from_optee(struct device *dev, int fw_id)
+{
+	struct arm_smccc_res res;
+	arm_smccc_smc(TEE_SMC_FAST_CALL_VAL(15), fw_id, 0, 0, 0, 0, 0, 0, &res);
+	dev_dbg(dev, "VDEC FW ID %d: %lu\n", fw_id, res.a0);
+}
+
+/* VDEC FW IDs */
+#define VDEC_MPEG12	0
+#define VDEC_H264	11
+#define VDEC_HEVC	16
+#define VDEC_HEVC_MMU	17
+#define VDEC_VP9	18
+#define VDEC_VP9_MMU	19
+
+int amvdec_load_firmware_optee(struct amvdec_session *sess)
+{
+	struct device *dev = sess->core->dev_dec;
+	u32 pixfmt = sess->fmt_out->pixfmt;
+	int fw_id = 1;
+
+	// Load wrong firmware to make TEE reset HW component for us
+	request_fw_from_optee(dev, fw_id);
+
+	if (pixfmt == V4L2_PIX_FMT_MPEG1 || pixfmt == V4L2_PIX_FMT_MPEG2)
+		fw_id = VDEC_MPEG12;
+
+	if (pixfmt == V4L2_PIX_FMT_H264)
+		fw_id = VDEC_H264;
+
+	if (pixfmt == V4L2_PIX_FMT_HEVC)
+		fw_id = VDEC_HEVC_MMU;
+
+	if (pixfmt == V4L2_PIX_FMT_VP9)
+		fw_id = VDEC_VP9_MMU;
+
+	request_fw_from_optee(dev, fw_id);
+	msleep(100); /*** REQUIRED??? ***/
+
+	return 0;
+}
diff --git a/drivers/staging/media/meson/vdec/optee.h b/drivers/staging/media/meson/vdec/optee.h
new file mode 100644
index 0000000000000..f4e209850ad8a
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/optee.h
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "vdec.h"
+
+int amvdec_load_firmware_optee(struct amvdec_session *sess);
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index de3e0345ab7c6..9acdbb0d53340 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -1029,6 +1029,9 @@ static int vdec_probe(struct platform_device *pdev)
 	of_id = of_match_node(vdec_dt_match, dev->of_node);
 	core->platform = of_id->data;
 
+	if (of_property_read_bool(dev->of_node, "amlogic,tee-loads-vdec-fw"))
+		core->use_optee = true;
+
 	if (core->platform->revision == VDEC_REVISION_G12A ||
 	    core->platform->revision == VDEC_REVISION_SM1) {
 		core->vdec_hevcf_clk = devm_clk_get(dev, "vdec_hevcf");
diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h
index 0906b8fb5cc60..274e8dae8c386 100644
--- a/drivers/staging/media/meson/vdec/vdec.h
+++ b/drivers/staging/media/meson/vdec/vdec.h
@@ -66,6 +66,7 @@ struct amvdec_session;
  * @v4l2_dev: v4l2 device
  * @cur_sess: current decoding session
  * @lock: video device lock
+ * @use_optee: request FW load from Trusted Execution Environment
  */
 struct amvdec_core {
 	void __iomem *dos_base;
@@ -91,6 +92,7 @@ struct amvdec_core {
 
 	struct amvdec_session *cur_sess;
 	struct mutex lock;
+	bool use_optee;
 };
 
 /**
diff --git a/drivers/staging/media/meson/vdec/vdec_1.c b/drivers/staging/media/meson/vdec/vdec_1.c
index 3fe2de0c9331f..0b46d72a5e0aa 100644
--- a/drivers/staging/media/meson/vdec/vdec_1.c
+++ b/drivers/staging/media/meson/vdec/vdec_1.c
@@ -13,6 +13,7 @@
 #include "vdec_1.h"
 #include "vdec_helpers.h"
 #include "dos_regs.h"
+#include "optee.h"
 
 /* AO Registers */
 #define AO_RTI_GEN_PWR_SLEEP0	0xe8
@@ -209,7 +210,11 @@ static int vdec_1_start(struct amvdec_session *sess)
 
 	vdec_1_stbuf_power_up(sess);
 
-	ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path);
+	if (core->use_optee)
+		ret = amvdec_load_firmware_optee(sess);
+	else
+		ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path);
+
 	if (ret)
 		goto stop;
 
@@ -232,6 +237,13 @@ static int vdec_1_start(struct amvdec_session *sess)
 	/* Let the firmware settle */
 	usleep_range(10, 20);
 
+	/*
+	 * When running secure boot, it looks like the codec needs
+	 * more time to settle (perhaps to authenticate the image?)
+	 */
+	if (core->use_optee)
+		msleep(100); /*** REQUIRED??? ***/
+
 	return 0;
 
 stop:
diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c
index afced435c9070..6d9141c5f3163 100644
--- a/drivers/staging/media/meson/vdec/vdec_hevc.c
+++ b/drivers/staging/media/meson/vdec/vdec_hevc.c
@@ -14,6 +14,7 @@
 #include "vdec_hevc.h"
 #include "hevc_regs.h"
 #include "dos_regs.h"
+#include "optee.h"
 
 /* AO Registers */
 #define AO_RTI_GEN_PWR_SLEEP0	0xe8
@@ -204,7 +205,10 @@ static int vdec_hevc_start(struct amvdec_session *sess)
 
 	vdec_hevc_stbuf_init(sess);
 
-	ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path);
+	if (core->use_optee)
+		ret = amvdec_load_firmware_optee(sess);
+	else
+		ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path);
 	if (ret)
 		goto stop;
 
@@ -220,6 +224,9 @@ static int vdec_hevc_start(struct amvdec_session *sess)
 	/* Let the firmware settle */
 	usleep_range(10, 20);
 
+	if (core->use_optee)
+		msleep(100); /*** REQUIRED??? ***/
+
 	return 0;
 
 stop:
-- 
2.34.1




More information about the linux-amlogic mailing list