@@ -167,7 +167,6 @@ hantro_vdev_to_func(struct video_device *vdev)
* @reg_bases: Mapped addresses of VPU registers.
* @enc_base: Mapped address of VPU encoder register for convenience.
* @dec_base: Mapped address of VPU decoder register for convenience.
- * @ctrl_base: Mapped address of VPU control block.
* @vpu_mutex: Mutex to synchronize V4L2 calls.
* @irqlock: Spinlock to synchronize access to data structures
* shared with interrupt handlers.
@@ -187,7 +186,6 @@ struct hantro_dev {
void __iomem **reg_bases;
void __iomem *enc_base;
void __iomem *dec_base;
- void __iomem *ctrl_base;
struct mutex vpu_mutex; /* video_device lock */
spinlock_t irqlock;
@@ -24,34 +24,13 @@
#define CTRL_G1_PP_FUSE 0x0c
#define CTRL_G2_DEC_FUSE 0x10
-static void imx8m_soft_reset(struct hantro_dev *vpu, u32 reset_bits)
-{
- u32 val;
-
- /* Assert */
- val = readl(vpu->ctrl_base + CTRL_SOFT_RESET);
- val &= ~reset_bits;
- writel(val, vpu->ctrl_base + CTRL_SOFT_RESET);
-
- udelay(2);
-
- /* Release */
- val = readl(vpu->ctrl_base + CTRL_SOFT_RESET);
- val |= reset_bits;
- writel(val, vpu->ctrl_base + CTRL_SOFT_RESET);
-}
-
-static void imx8m_clk_enable(struct hantro_dev *vpu, u32 clock_bits)
-{
- u32 val;
-
- val = readl(vpu->ctrl_base + CTRL_CLOCK_ENABLE);
- val |= clock_bits;
- writel(val, vpu->ctrl_base + CTRL_CLOCK_ENABLE);
-}
-
-static int imx8mq_runtime_resume(struct hantro_dev *vpu)
+/*
+ * Due to a HW limitation, both G1 and G2 VPU cores on imx8mq need to be reset
+ * together via their unified ctrl block.
+ */
+static int imx8mq_ctrlblk_reset(struct hantro_dev *vpu)
{
+ void __iomem *ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1];
int ret;
ret = clk_bulk_prepare_enable(vpu->variant->num_clocks, vpu->clocks);
@@ -60,13 +39,18 @@ static int imx8mq_runtime_resume(struct hantro_dev *vpu)
return ret;
}
- imx8m_soft_reset(vpu, RESET_G1 | RESET_G2);
- imx8m_clk_enable(vpu, CLOCK_G1 | CLOCK_G2);
+ /* reset HW and ungate clocks via ctrl block */
+ writel(RESET_G1 | RESET_G2, ctrl_base + CTRL_SOFT_RESET);
+ writel(CLOCK_G1 | CLOCK_G2, ctrl_base + CTRL_CLOCK_ENABLE);
- /* Set values of the fuse registers */
- writel(0xffffffff, vpu->ctrl_base + CTRL_G1_DEC_FUSE);
- writel(0xffffffff, vpu->ctrl_base + CTRL_G1_PP_FUSE);
- writel(0xffffffff, vpu->ctrl_base + CTRL_G2_DEC_FUSE);
+ /*
+ * enable fuse functionalities for each core, these are not real fuses
+ * but registers which enable the cores and makes accesible their real
+ * read-only fuse registers describing supported features.
+ */
+ writel(0xffffffff, ctrl_base + CTRL_G1_DEC_FUSE);
+ writel(0xffffffff, ctrl_base + CTRL_G1_PP_FUSE);
+ writel(0xffffffff, ctrl_base + CTRL_G2_DEC_FUSE);
clk_bulk_disable_unprepare(vpu->variant->num_clocks, vpu->clocks);
@@ -148,19 +132,9 @@ static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int imx8mq_vpu_hw_init(struct hantro_dev *vpu)
+static void imx8m_vpu_reset(struct hantro_ctx *ctx)
{
- vpu->dec_base = vpu->reg_bases[0];
- vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1];
-
- return 0;
-}
-
-static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx)
-{
- struct hantro_dev *vpu = ctx->dev;
-
- imx8m_soft_reset(vpu, RESET_G1);
+ imx8mq_ctrlblk_reset(ctx->dev);
}
/*
@@ -170,19 +144,19 @@ static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx)
static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = {
[HANTRO_MODE_MPEG2_DEC] = {
.run = hantro_g1_mpeg2_dec_run,
- .reset = imx8m_vpu_g1_reset,
+ .reset = imx8m_vpu_reset,
.init = hantro_mpeg2_dec_init,
.exit = hantro_mpeg2_dec_exit,
},
[HANTRO_MODE_VP8_DEC] = {
.run = hantro_g1_vp8_dec_run,
- .reset = imx8m_vpu_g1_reset,
+ .reset = imx8m_vpu_reset,
.init = hantro_vp8_dec_init,
.exit = hantro_vp8_dec_exit,
},
[HANTRO_MODE_H264_DEC] = {
.run = hantro_g1_h264_dec_run,
- .reset = imx8m_vpu_g1_reset,
+ .reset = imx8m_vpu_reset,
.init = hantro_h264_dec_init,
.exit = hantro_h264_dec_exit,
},
@@ -209,8 +183,8 @@ const struct hantro_variant imx8mq_vpu_variant = {
.codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
HANTRO_H264_DECODER,
.codec_ops = imx8mq_vpu_codec_ops,
- .init = imx8mq_vpu_hw_init,
- .runtime_resume = imx8mq_runtime_resume,
+ .init = imx8mq_ctrlblk_reset,
+ .runtime_resume = imx8mq_ctrlblk_reset,
.irqs = imx8mq_irqs,
.num_irqs = ARRAY_SIZE(imx8mq_irqs),
.clk_names = imx8mq_clk_names,
The G1 and G2 cores on imx8mq share a common "control block" used to reset and enable the core clocks as well as enable functioning via ctrl FUSE registers (these are not the FUSEs on the VPU cores, they are just used to enable/disable the cores and allow the real VPU FUSE regs to become available). The problem is that, while the cores can be operated independently from one another (different config reg mem regions, separate IRQs), they can not be reset or powered down independently as the current code implies. This has been a source for many bugs and frustration when trying to enable G2 which this driver does not support yet. So we simplify the ctrlblk reset logic to always reset both cores, exactly like the vendor linux-imx provided driver "hantrodec" does for this SoC. Going forward, this simplified code should be moved in the future to its own reset controller driver as the reset framework also supports shared reset resources so the runtime PM logic can disable both cores when none of them are in use (this is not done yet because only G1 is supported in the driver so there is no need to account for G2). Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> --- drivers/staging/media/hantro/hantro.h | 2 - drivers/staging/media/hantro/imx8m_vpu_hw.c | 74 +++++++-------------- 2 files changed, 24 insertions(+), 52 deletions(-)