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