linux/drivers/staging/media/hantro/imx8m_vpu_hw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Hantro VPU codec driver
   4 *
   5 * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
   6 */
   7
   8#include <linux/clk.h>
   9#include <linux/delay.h>
  10
  11#include "hantro.h"
  12#include "hantro_jpeg.h"
  13#include "hantro_g1_regs.h"
  14#include "hantro_g2_regs.h"
  15
  16#define CTRL_SOFT_RESET         0x00
  17#define RESET_G1                BIT(1)
  18#define RESET_G2                BIT(0)
  19
  20#define CTRL_CLOCK_ENABLE       0x04
  21#define CLOCK_G1                BIT(1)
  22#define CLOCK_G2                BIT(0)
  23
  24#define CTRL_G1_DEC_FUSE        0x08
  25#define CTRL_G1_PP_FUSE         0x0c
  26#define CTRL_G2_DEC_FUSE        0x10
  27
  28static void imx8m_soft_reset(struct hantro_dev *vpu, u32 reset_bits)
  29{
  30        u32 val;
  31
  32        /* Assert */
  33        val = readl(vpu->ctrl_base + CTRL_SOFT_RESET);
  34        val &= ~reset_bits;
  35        writel(val, vpu->ctrl_base + CTRL_SOFT_RESET);
  36
  37        udelay(2);
  38
  39        /* Release */
  40        val = readl(vpu->ctrl_base + CTRL_SOFT_RESET);
  41        val |= reset_bits;
  42        writel(val, vpu->ctrl_base + CTRL_SOFT_RESET);
  43}
  44
  45static void imx8m_clk_enable(struct hantro_dev *vpu, u32 clock_bits)
  46{
  47        u32 val;
  48
  49        val = readl(vpu->ctrl_base + CTRL_CLOCK_ENABLE);
  50        val |= clock_bits;
  51        writel(val, vpu->ctrl_base + CTRL_CLOCK_ENABLE);
  52}
  53
  54static int imx8mq_runtime_resume(struct hantro_dev *vpu)
  55{
  56        int ret;
  57
  58        ret = clk_bulk_prepare_enable(vpu->variant->num_clocks, vpu->clocks);
  59        if (ret) {
  60                dev_err(vpu->dev, "Failed to enable clocks\n");
  61                return ret;
  62        }
  63
  64        imx8m_soft_reset(vpu, RESET_G1 | RESET_G2);
  65        imx8m_clk_enable(vpu, CLOCK_G1 | CLOCK_G2);
  66
  67        /* Set values of the fuse registers */
  68        writel(0xffffffff, vpu->ctrl_base + CTRL_G1_DEC_FUSE);
  69        writel(0xffffffff, vpu->ctrl_base + CTRL_G1_PP_FUSE);
  70        writel(0xffffffff, vpu->ctrl_base + CTRL_G2_DEC_FUSE);
  71
  72        clk_bulk_disable_unprepare(vpu->variant->num_clocks, vpu->clocks);
  73
  74        return 0;
  75}
  76
  77/*
  78 * Supported formats.
  79 */
  80
  81static const struct hantro_fmt imx8m_vpu_postproc_fmts[] = {
  82        {
  83                .fourcc = V4L2_PIX_FMT_YUYV,
  84                .codec_mode = HANTRO_MODE_NONE,
  85        },
  86};
  87
  88static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
  89        {
  90                .fourcc = V4L2_PIX_FMT_NV12,
  91                .codec_mode = HANTRO_MODE_NONE,
  92        },
  93        {
  94                .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
  95                .codec_mode = HANTRO_MODE_MPEG2_DEC,
  96                .max_depth = 2,
  97                .frmsize = {
  98                        .min_width = 48,
  99                        .max_width = 1920,
 100                        .step_width = MB_DIM,
 101                        .min_height = 48,
 102                        .max_height = 1088,
 103                        .step_height = MB_DIM,
 104                },
 105        },
 106        {
 107                .fourcc = V4L2_PIX_FMT_VP8_FRAME,
 108                .codec_mode = HANTRO_MODE_VP8_DEC,
 109                .max_depth = 2,
 110                .frmsize = {
 111                        .min_width = 48,
 112                        .max_width = 3840,
 113                        .step_width = MB_DIM,
 114                        .min_height = 48,
 115                        .max_height = 2160,
 116                        .step_height = MB_DIM,
 117                },
 118        },
 119        {
 120                .fourcc = V4L2_PIX_FMT_H264_SLICE,
 121                .codec_mode = HANTRO_MODE_H264_DEC,
 122                .max_depth = 2,
 123                .frmsize = {
 124                        .min_width = 48,
 125                        .max_width = 3840,
 126                        .step_width = MB_DIM,
 127                        .min_height = 48,
 128                        .max_height = 2160,
 129                        .step_height = MB_DIM,
 130                },
 131        },
 132};
 133
 134static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = {
 135        {
 136                .fourcc = V4L2_PIX_FMT_NV12,
 137                .codec_mode = HANTRO_MODE_NONE,
 138        },
 139        {
 140                .fourcc = V4L2_PIX_FMT_HEVC_SLICE,
 141                .codec_mode = HANTRO_MODE_HEVC_DEC,
 142                .max_depth = 2,
 143                .frmsize = {
 144                        .min_width = 48,
 145                        .max_width = 3840,
 146                        .step_width = MB_DIM,
 147                        .min_height = 48,
 148                        .max_height = 2160,
 149                        .step_height = MB_DIM,
 150                },
 151        },
 152};
 153
 154static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
 155{
 156        struct hantro_dev *vpu = dev_id;
 157        enum vb2_buffer_state state;
 158        u32 status;
 159
 160        status = vdpu_read(vpu, G1_REG_INTERRUPT);
 161        state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ?
 162                 VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
 163
 164        vdpu_write(vpu, 0, G1_REG_INTERRUPT);
 165        vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
 166
 167        hantro_irq_done(vpu, state);
 168
 169        return IRQ_HANDLED;
 170}
 171
 172static irqreturn_t imx8m_vpu_g2_irq(int irq, void *dev_id)
 173{
 174        struct hantro_dev *vpu = dev_id;
 175        enum vb2_buffer_state state;
 176        u32 status;
 177
 178        status = vdpu_read(vpu, G2_REG_INTERRUPT);
 179        state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ?
 180                 VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
 181
 182        vdpu_write(vpu, 0, G2_REG_INTERRUPT);
 183        vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG);
 184
 185        hantro_irq_done(vpu, state);
 186
 187        return IRQ_HANDLED;
 188}
 189
 190static int imx8mq_vpu_hw_init(struct hantro_dev *vpu)
 191{
 192        vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1];
 193
 194        return 0;
 195}
 196
 197static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx)
 198{
 199        struct hantro_dev *vpu = ctx->dev;
 200
 201        imx8m_soft_reset(vpu, RESET_G1);
 202}
 203
 204static void imx8m_vpu_g2_reset(struct hantro_ctx *ctx)
 205{
 206        struct hantro_dev *vpu = ctx->dev;
 207
 208        imx8m_soft_reset(vpu, RESET_G2);
 209}
 210
 211/*
 212 * Supported codec ops.
 213 */
 214
 215static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = {
 216        [HANTRO_MODE_MPEG2_DEC] = {
 217                .run = hantro_g1_mpeg2_dec_run,
 218                .reset = imx8m_vpu_g1_reset,
 219                .init = hantro_mpeg2_dec_init,
 220                .exit = hantro_mpeg2_dec_exit,
 221        },
 222        [HANTRO_MODE_VP8_DEC] = {
 223                .run = hantro_g1_vp8_dec_run,
 224                .reset = imx8m_vpu_g1_reset,
 225                .init = hantro_vp8_dec_init,
 226                .exit = hantro_vp8_dec_exit,
 227        },
 228        [HANTRO_MODE_H264_DEC] = {
 229                .run = hantro_g1_h264_dec_run,
 230                .reset = imx8m_vpu_g1_reset,
 231                .init = hantro_h264_dec_init,
 232                .exit = hantro_h264_dec_exit,
 233        },
 234};
 235
 236static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = {
 237        [HANTRO_MODE_HEVC_DEC] = {
 238                .run = hantro_g2_hevc_dec_run,
 239                .reset = imx8m_vpu_g2_reset,
 240                .init = hantro_hevc_dec_init,
 241                .exit = hantro_hevc_dec_exit,
 242        },
 243};
 244
 245/*
 246 * VPU variants.
 247 */
 248
 249static const struct hantro_irq imx8mq_irqs[] = {
 250        { "g1", imx8m_vpu_g1_irq },
 251};
 252
 253static const struct hantro_irq imx8mq_g2_irqs[] = {
 254        { "g2", imx8m_vpu_g2_irq },
 255};
 256
 257static const char * const imx8mq_clk_names[] = { "g1", "g2", "bus" };
 258static const char * const imx8mq_reg_names[] = { "g1", "g2", "ctrl" };
 259
 260const struct hantro_variant imx8mq_vpu_variant = {
 261        .dec_fmts = imx8m_vpu_dec_fmts,
 262        .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
 263        .postproc_fmts = imx8m_vpu_postproc_fmts,
 264        .num_postproc_fmts = ARRAY_SIZE(imx8m_vpu_postproc_fmts),
 265        .postproc_regs = &hantro_g1_postproc_regs,
 266        .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
 267                 HANTRO_H264_DECODER,
 268        .codec_ops = imx8mq_vpu_codec_ops,
 269        .init = imx8mq_vpu_hw_init,
 270        .runtime_resume = imx8mq_runtime_resume,
 271        .irqs = imx8mq_irqs,
 272        .num_irqs = ARRAY_SIZE(imx8mq_irqs),
 273        .clk_names = imx8mq_clk_names,
 274        .num_clocks = ARRAY_SIZE(imx8mq_clk_names),
 275        .reg_names = imx8mq_reg_names,
 276        .num_regs = ARRAY_SIZE(imx8mq_reg_names)
 277};
 278
 279const struct hantro_variant imx8mq_vpu_g2_variant = {
 280        .dec_offset = 0x0,
 281        .dec_fmts = imx8m_vpu_g2_dec_fmts,
 282        .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_g2_dec_fmts),
 283        .codec = HANTRO_HEVC_DECODER,
 284        .codec_ops = imx8mq_vpu_g2_codec_ops,
 285        .init = imx8mq_vpu_hw_init,
 286        .runtime_resume = imx8mq_runtime_resume,
 287        .irqs = imx8mq_g2_irqs,
 288        .num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
 289        .clk_names = imx8mq_clk_names,
 290        .num_clocks = ARRAY_SIZE(imx8mq_clk_names),
 291};
 292