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 16 static 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 34 static 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 41 static 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 51 static 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 190 static 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 202 struct 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