@@ -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:
@@ -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
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "vdec.h"
+
+int amvdec_load_firmware_optee(struct amvdec_session *sess);
@@ -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");
@@ -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;
};
/**
@@ -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:
@@ -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: