linux/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Cedrus VPU driver
   4 *
   5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
   6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
   7 * Copyright (C) 2018 Bootlin
   8 */
   9
  10#include <media/videobuf2-dma-contig.h>
  11
  12#include "cedrus.h"
  13#include "cedrus_hw.h"
  14#include "cedrus_regs.h"
  15
  16static enum cedrus_irq_status cedrus_mpeg2_irq_status(struct cedrus_ctx *ctx)
  17{
  18        struct cedrus_dev *dev = ctx->dev;
  19        u32 reg;
  20
  21        reg = cedrus_read(dev, VE_DEC_MPEG_STATUS);
  22        reg &= VE_DEC_MPEG_STATUS_CHECK_MASK;
  23
  24        if (!reg)
  25                return CEDRUS_IRQ_NONE;
  26
  27        if (reg & VE_DEC_MPEG_STATUS_CHECK_ERROR ||
  28            !(reg & VE_DEC_MPEG_STATUS_SUCCESS))
  29                return CEDRUS_IRQ_ERROR;
  30
  31        return CEDRUS_IRQ_OK;
  32}
  33
  34static void cedrus_mpeg2_irq_clear(struct cedrus_ctx *ctx)
  35{
  36        struct cedrus_dev *dev = ctx->dev;
  37
  38        cedrus_write(dev, VE_DEC_MPEG_STATUS, VE_DEC_MPEG_STATUS_CHECK_MASK);
  39}
  40
  41static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx)
  42{
  43        struct cedrus_dev *dev = ctx->dev;
  44        u32 reg = cedrus_read(dev, VE_DEC_MPEG_CTRL);
  45
  46        reg &= ~VE_DEC_MPEG_CTRL_IRQ_MASK;
  47
  48        cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
  49}
  50
  51static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
  52{
  53        const struct v4l2_ctrl_mpeg2_sequence *seq;
  54        const struct v4l2_ctrl_mpeg2_picture *pic;
  55        const struct v4l2_ctrl_mpeg2_quantisation *quantisation;
  56        dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
  57        dma_addr_t fwd_luma_addr, fwd_chroma_addr;
  58        dma_addr_t bwd_luma_addr, bwd_chroma_addr;
  59        struct cedrus_dev *dev = ctx->dev;
  60        struct vb2_queue *vq;
  61        const u8 *matrix;
  62        int forward_idx;
  63        int backward_idx;
  64        unsigned int i;
  65        u32 reg;
  66
  67        seq = run->mpeg2.sequence;
  68        pic = run->mpeg2.picture;
  69
  70        quantisation = run->mpeg2.quantisation;
  71
  72        /* Activate MPEG engine. */
  73        cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2);
  74
  75        /* Set intra quantisation matrix. */
  76        matrix = quantisation->intra_quantiser_matrix;
  77        for (i = 0; i < 64; i++) {
  78                reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
  79                reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA;
  80
  81                cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
  82        }
  83
  84        /* Set non-intra quantisation matrix. */
  85        matrix = quantisation->non_intra_quantiser_matrix;
  86        for (i = 0; i < 64; i++) {
  87                reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
  88                reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA;
  89
  90                cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
  91        }
  92
  93        /* Set MPEG picture header. */
  94
  95        reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(pic->picture_coding_type);
  96        reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, pic->f_code[0][0]);
  97        reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, pic->f_code[0][1]);
  98        reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, pic->f_code[1][0]);
  99        reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, pic->f_code[1][1]);
 100        reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(pic->intra_dc_precision);
 101        reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(pic->picture_structure);
 102        reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST);
 103        reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT);
 104        reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV);
 105        reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE);
 106        reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC);
 107        reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN);
 108        reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0);
 109        reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0);
 110
 111        cedrus_write(dev, VE_DEC_MPEG_MP12HDR, reg);
 112
 113        /* Set frame dimensions. */
 114
 115        reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(seq->horizontal_size);
 116        reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(seq->vertical_size);
 117
 118        cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg);
 119
 120        reg = VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(ctx->src_fmt.width);
 121        reg |= VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(ctx->src_fmt.height);
 122
 123        cedrus_write(dev, VE_DEC_MPEG_PICBOUNDSIZE, reg);
 124
 125        /* Forward and backward prediction reference buffers. */
 126
 127        vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
 128
 129        forward_idx = vb2_find_timestamp(vq, pic->forward_ref_ts, 0);
 130        fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0);
 131        fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1);
 132
 133        cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr);
 134        cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr);
 135
 136        backward_idx = vb2_find_timestamp(vq, pic->backward_ref_ts, 0);
 137        bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0);
 138        bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1);
 139
 140        cedrus_write(dev, VE_DEC_MPEG_BWD_REF_LUMA_ADDR, bwd_luma_addr);
 141        cedrus_write(dev, VE_DEC_MPEG_BWD_REF_CHROMA_ADDR, bwd_chroma_addr);
 142
 143        /* Destination luma and chroma buffers. */
 144
 145        dst_luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0);
 146        dst_chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1);
 147
 148        cedrus_write(dev, VE_DEC_MPEG_REC_LUMA, dst_luma_addr);
 149        cedrus_write(dev, VE_DEC_MPEG_REC_CHROMA, dst_chroma_addr);
 150
 151        /* Source offset and length in bits. */
 152
 153        cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET, 0);
 154
 155        reg = vb2_get_plane_payload(&run->src->vb2_buf, 0) * 8;
 156        cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg);
 157
 158        /* Source beginning and end addresses. */
 159
 160        src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
 161
 162        reg = VE_DEC_MPEG_VLD_ADDR_BASE(src_buf_addr);
 163        reg |= VE_DEC_MPEG_VLD_ADDR_VALID_PIC_DATA;
 164        reg |= VE_DEC_MPEG_VLD_ADDR_LAST_PIC_DATA;
 165        reg |= VE_DEC_MPEG_VLD_ADDR_FIRST_PIC_DATA;
 166
 167        cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg);
 168
 169        reg = src_buf_addr + vb2_get_plane_payload(&run->src->vb2_buf, 0);
 170        cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg);
 171
 172        /* Macroblock address: start at the beginning. */
 173        reg = VE_DEC_MPEG_MBADDR_Y(0) | VE_DEC_MPEG_MBADDR_X(0);
 174        cedrus_write(dev, VE_DEC_MPEG_MBADDR, reg);
 175
 176        /* Clear previous errors. */
 177        cedrus_write(dev, VE_DEC_MPEG_ERROR, 0);
 178
 179        /* Clear correct macroblocks register. */
 180        cedrus_write(dev, VE_DEC_MPEG_CRTMBADDR, 0);
 181
 182        /* Enable appropriate interruptions and components. */
 183
 184        reg = VE_DEC_MPEG_CTRL_IRQ_MASK | VE_DEC_MPEG_CTRL_MC_NO_WRITEBACK |
 185              VE_DEC_MPEG_CTRL_MC_CACHE_EN;
 186
 187        cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
 188}
 189
 190static void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
 191{
 192        struct cedrus_dev *dev = ctx->dev;
 193        u32 reg;
 194
 195        /* Trigger MPEG engine. */
 196        reg = VE_DEC_MPEG_TRIGGER_HW_MPEG_VLD | VE_DEC_MPEG_TRIGGER_MPEG2 |
 197              VE_DEC_MPEG_TRIGGER_MB_BOUNDARY;
 198
 199        cedrus_write(dev, VE_DEC_MPEG_TRIGGER, reg);
 200}
 201
 202struct cedrus_dec_ops cedrus_dec_ops_mpeg2 = {
 203        .irq_clear      = cedrus_mpeg2_irq_clear,
 204        .irq_disable    = cedrus_mpeg2_irq_disable,
 205        .irq_status     = cedrus_mpeg2_irq_status,
 206        .setup          = cedrus_mpeg2_setup,
 207        .trigger        = cedrus_mpeg2_trigger,
 208};
 209