[PATCH v2 12/34] media: iris: add video processing unit(VPU) specific register handling

From: Dikshita Agarwal
Date: Mon Dec 18 2023 - 06:35:13 EST


Registers are defined differently for different VPUs.
Define ops for VPU specific handling to accommodate
different VPUs. Implement boot sequence of firmware and interrupt
programming.

Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx>
---
drivers/media/platform/qcom/vcodec/iris/Makefile | 4 +-
.../media/platform/qcom/vcodec/iris/iris_core.h | 3 +
drivers/media/platform/qcom/vcodec/iris/iris_hfi.c | 7 +
.../media/platform/qcom/vcodec/iris/iris_probe.c | 7 +
.../media/platform/qcom/vcodec/iris/vpu_common.c | 71 +++++++++
.../media/platform/qcom/vcodec/iris/vpu_common.h | 32 ++++
.../media/platform/qcom/vcodec/iris/vpu_iris3.c | 166 +++++++++++++++++++++
.../media/platform/qcom/vcodec/iris/vpu_iris3.h | 13 ++
8 files changed, 302 insertions(+), 1 deletion(-)
create mode 100644 drivers/media/platform/qcom/vcodec/iris/vpu_common.c
create mode 100644 drivers/media/platform/qcom/vcodec/iris/vpu_common.h
create mode 100644 drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
create mode 100644 drivers/media/platform/qcom/vcodec/iris/vpu_iris3.h

diff --git a/drivers/media/platform/qcom/vcodec/iris/Makefile b/drivers/media/platform/qcom/vcodec/iris/Makefile
index a2d5d74..90241b5 100644
--- a/drivers/media/platform/qcom/vcodec/iris/Makefile
+++ b/drivers/media/platform/qcom/vcodec/iris/Makefile
@@ -7,6 +7,8 @@ iris-objs += iris_probe.o \
iris_helpers.o \
iris_hfi.o \
iris_hfi_packet.o \
- resources.o
+ resources.o \
+ vpu_common.o \
+ vpu_iris3.o

obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_core.h b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
index de0cfef..64678fd 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_core.h
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_core.h
@@ -12,6 +12,7 @@
#include "../hfi_queue.h"
#include "iris_state.h"
#include "resources.h"
+#include "vpu_common.h"

/**
* struct iris_core - holds core parameters valid for all instances
@@ -44,6 +45,7 @@
* @sys_init_id: id of sys init packet
* @header_id: id of packet header
* @packet_id: id of packet
+ * @vpu_ops: a pointer to vpu ops
*/

struct iris_core {
@@ -75,6 +77,7 @@ struct iris_core {
u32 sys_init_id;
u32 header_id;
u32 packet_id;
+ const struct vpu_ops *vpu_ops;
};

int iris_core_init(struct iris_core *core);
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
index fe16448..7b3cbbc 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_hfi.c
@@ -8,6 +8,7 @@
#include "iris_helpers.h"
#include "iris_hfi.h"
#include "iris_hfi_packet.h"
+#include "vpu_common.h"

static int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt)
{
@@ -33,6 +34,8 @@ static int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt)
packet_size = header->size;

if (!write_queue(q_info, pkt, packet_size, &rx_req)) {
+ call_vpu_op(core, raise_interrupt, core);
+ } else {
dev_err(core->dev, "queue full\n");
return -ENODATA;
}
@@ -108,6 +111,10 @@ int iris_hfi_core_init(struct iris_core *core)
if (ret)
goto error;

+ ret = call_vpu_op(core, boot_firmware, core);
+ if (ret)
+ goto error;
+
ret = sys_init(core);
if (ret)
goto error;
diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
index 570c64e..773481f 100644
--- a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c
@@ -92,6 +92,13 @@ static int iris_probe(struct platform_device *pdev)
if (core->irq < 0)
return core->irq;

+ ret = init_vpu(core);
+ if (ret) {
+ dev_err_probe(core->dev, ret,
+ "%s: init vpu failed with %d\n", __func__, ret);
+ return ret;
+ }
+
ret = init_resources(core);
if (ret) {
dev_err_probe(core->dev, ret,
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_common.c b/drivers/media/platform/qcom/vcodec/iris/vpu_common.c
new file mode 100644
index 0000000..3282510
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_common.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "vpu_iris3.h"
+#include "iris_core.h"
+#include "iris_helpers.h"
+#include "vpu_common.h"
+
+int write_register(struct iris_core *core, u32 reg, u32 value)
+{
+ void __iomem *base_addr;
+ int ret;
+
+ ret = check_core_lock(core);
+ if (ret)
+ return ret;
+
+ base_addr = core->reg_base;
+ base_addr += reg;
+ writel_relaxed(value, base_addr);
+
+ /* Make sure value is written into the register */
+ wmb();
+
+ return ret;
+}
+
+int read_register(struct iris_core *core, u32 reg, u32 *value)
+{
+ void __iomem *base_addr;
+
+ base_addr = core->reg_base;
+
+ *value = readl_relaxed(base_addr + reg);
+
+ /* Make sure value is read correctly from the register */
+ rmb();
+
+ return 0;
+}
+
+static const struct compat_handle compat_handle[] = {
+ {
+ .compat = "qcom,sm8550-iris",
+ .init = init_iris3,
+ },
+};
+
+int init_vpu(struct iris_core *core)
+{
+ struct device *dev = NULL;
+ int i, ret = 0;
+
+ dev = core->dev;
+
+ for (i = 0; i < ARRAY_SIZE(compat_handle); i++) {
+ if (of_device_is_compatible(dev->of_node, compat_handle[i].compat)) {
+ ret = compat_handle[i].init(core);
+ if (ret)
+ return ret;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(compat_handle))
+ return -EINVAL;
+
+ return ret;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_common.h b/drivers/media/platform/qcom/vcodec/iris/vpu_common.h
new file mode 100644
index 0000000..790496a
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_common.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _VPU_COMMON_H_
+#define _VPU_COMMON_H_
+
+#include <linux/types.h>
+
+struct iris_core;
+
+#define call_vpu_op(d, op, ...) \
+ (((d) && (d)->vpu_ops && (d)->vpu_ops->op) ? \
+ ((d)->vpu_ops->op(__VA_ARGS__)) : 0)
+
+struct compat_handle {
+ const char *compat;
+ int (*init)(struct iris_core *core);
+};
+
+struct vpu_ops {
+ int (*boot_firmware)(struct iris_core *core);
+ int (*raise_interrupt)(struct iris_core *core);
+};
+
+int init_vpu(struct iris_core *core);
+
+int write_register(struct iris_core *core, u32 reg, u32 value);
+int read_register(struct iris_core *core, u32 reg, u32 *value);
+
+#endif
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
new file mode 100644
index 0000000..95bf223
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/delay.h>
+
+#include "vpu_iris3.h"
+
+#define VIDEO_ARCH_LX 1
+
+#define CPU_BASE_OFFS_IRIS3 0x000A0000
+
+#define CPU_CS_BASE_OFFS_IRIS3 (CPU_BASE_OFFS_IRIS3)
+#define CPU_IC_BASE_OFFS_IRIS3 (CPU_BASE_OFFS_IRIS3)
+
+#define CPU_CS_VCICMDARG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x24)
+#define CPU_CS_VCICMDARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x28)
+
+/* HFI_CTRL_INIT */
+#define CPU_CS_SCIACMD_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x48)
+
+/* HFI_CTRL_STATUS */
+#define CPU_CS_SCIACMDARG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x4C)
+#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3 0x40000000
+
+#define CPU_CS_H2XSOFTINTEN_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x148)
+
+#define CPU_CS_X2RPMH_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x168)
+
+/* UC_REGION_ADDR */
+#define CPU_CS_SCIBARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x64)
+
+/* UC_REGION_ADDR */
+#define CPU_CS_SCIBARG2_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x68)
+
+/* HFI_QTBL_INFO */
+#define CPU_CS_SCIACMDARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x50)
+
+/* HFI_QTBL_ADDR */
+#define CPU_CS_SCIACMDARG2_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x54)
+
+/* SFR_ADDR */
+#define CPU_CS_SCIBCMD_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x5C)
+
+#define UC_REGION_ADDR_IRIS3 CPU_CS_SCIBARG1_IRIS3
+#define UC_REGION_SIZE_IRIS3 CPU_CS_SCIBARG2_IRIS3
+
+#define QTBL_INFO_IRIS3 CPU_CS_SCIACMDARG1_IRIS3
+#define QTBL_ADDR_IRIS3 CPU_CS_SCIACMDARG2_IRIS3
+
+#define SFR_ADDR_IRIS3 CPU_CS_SCIBCMD_IRIS3
+
+#define CTRL_INIT_IRIS3 CPU_CS_SCIACMD_IRIS3
+
+#define CTRL_STATUS_IRIS3 CPU_CS_SCIACMDARG0_IRIS3
+#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3 0xfe
+#define CTRL_ERROR_STATUS__M_IRIS3 \
+ CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3
+
+#define CPU_IC_SOFTINT_IRIS3 (CPU_IC_BASE_OFFS_IRIS3 + 0x150)
+#define CPU_IC_SOFTINT_H2A_SHFT_IRIS3 0x0
+
+static int setup_ucregion_memory_map_iris3(struct iris_core *core)
+{
+ int ret;
+ u32 value;
+
+ value = (u32)core->iface_q_table.device_addr;
+ ret = write_register(core, UC_REGION_ADDR_IRIS3, value);
+ if (ret)
+ return ret;
+
+ value = SHARED_QSIZE;
+ ret = write_register(core, UC_REGION_SIZE_IRIS3, value);
+ if (ret)
+ return ret;
+
+ value = (u32)core->iface_q_table.device_addr;
+ ret = write_register(core, QTBL_ADDR_IRIS3, value);
+ if (ret)
+ return ret;
+
+ ret = write_register(core, QTBL_INFO_IRIS3, 0x01);
+ if (ret)
+ return ret;
+
+ value = (u32)((u64)core->iface_q_table.kernel_vaddr);
+ ret = write_register(core, CPU_CS_VCICMDARG0_IRIS3, value);
+ if (ret)
+ return ret;
+
+ value = (u32)((u64)core->iface_q_table.kernel_vaddr >> 32);
+ ret = write_register(core, CPU_CS_VCICMDARG1_IRIS3, value);
+ if (ret)
+ return ret;
+
+ if (core->sfr.device_addr) {
+ value = (u32)core->sfr.device_addr + VIDEO_ARCH_LX;
+ ret = write_register(core, SFR_ADDR_IRIS3, value);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int boot_firmware_iris3(struct iris_core *core)
+{
+ u32 ctrl_init = 0, ctrl_status = 0, count = 0, max_tries = 1000;
+ int ret;
+
+ ret = setup_ucregion_memory_map_iris3(core);
+ if (ret)
+ return ret;
+
+ ctrl_init = BIT(0);
+
+ ret = write_register(core, CTRL_INIT_IRIS3, ctrl_init);
+ if (ret)
+ return ret;
+
+ while (!ctrl_status && count < max_tries) {
+ ret = read_register(core, CTRL_STATUS_IRIS3, &ctrl_status);
+ if (ret)
+ return ret;
+
+ if ((ctrl_status & CTRL_ERROR_STATUS__M_IRIS3) == 0x4) {
+ dev_err(core->dev, "invalid setting for UC_REGION\n");
+ break;
+ }
+
+ usleep_range(50, 100);
+ count++;
+ }
+
+ if (count >= max_tries) {
+ dev_err(core->dev, "Error booting up vidc firmware\n");
+ return -ETIME;
+ }
+
+ ret = write_register(core, CPU_CS_H2XSOFTINTEN_IRIS3, 0x1);
+ if (ret)
+ return ret;
+
+ ret = write_register(core, CPU_CS_X2RPMH_IRIS3, 0x0);
+
+ return ret;
+}
+
+static int raise_interrupt_iris3(struct iris_core *core)
+{
+ return write_register(core, CPU_IC_SOFTINT_IRIS3, 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS3);
+}
+
+static const struct vpu_ops iris3_ops = {
+ .boot_firmware = boot_firmware_iris3,
+ .raise_interrupt = raise_interrupt_iris3,
+};
+
+int init_iris3(struct iris_core *core)
+{
+ core->vpu_ops = &iris3_ops;
+
+ return 0;
+}
diff --git a/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.h b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.h
new file mode 100644
index 0000000..1424a5f
--- /dev/null
+++ b/drivers/media/platform/qcom/vcodec/iris/vpu_iris3.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _VPU_IRIS3_H_
+#define _VPU_IRIS3_H_
+
+#include "iris_core.h"
+
+int init_iris3(struct iris_core *core);
+
+#endif
--
2.7.4