[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