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
cedrus_mpeg2_irq_status(struct cedrus_ctx * ctx)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
cedrus_mpeg2_irq_clear(struct cedrus_ctx * ctx)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
cedrus_mpeg2_irq_disable(struct cedrus_ctx * ctx)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
cedrus_mpeg2_setup(struct cedrus_ctx * ctx,struct cedrus_run * run)51 static int 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 struct cedrus_dev *dev = ctx->dev;
58 struct vb2_queue *vq;
59 const u8 *matrix;
60 unsigned int i;
61 u32 reg;
62
63 seq = run->mpeg2.sequence;
64 pic = run->mpeg2.picture;
65
66 quantisation = run->mpeg2.quantisation;
67
68 /* Activate MPEG engine. */
69 cedrus_engine_enable(ctx);
70
71 /* Set intra quantisation matrix. */
72 matrix = quantisation->intra_quantiser_matrix;
73 for (i = 0; i < 64; i++) {
74 reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
75 reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA;
76
77 cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
78 }
79
80 /* Set non-intra quantisation matrix. */
81 matrix = quantisation->non_intra_quantiser_matrix;
82 for (i = 0; i < 64; i++) {
83 reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
84 reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA;
85
86 cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
87 }
88
89 /* Set MPEG picture header. */
90
91 reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(pic->picture_coding_type);
92 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, pic->f_code[0][0]);
93 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, pic->f_code[0][1]);
94 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, pic->f_code[1][0]);
95 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, pic->f_code[1][1]);
96 reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(pic->intra_dc_precision);
97 reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(pic->picture_structure);
98 reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST);
99 reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT);
100 reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV);
101 reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE);
102 reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC);
103 reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN);
104 reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0);
105 reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0);
106
107 cedrus_write(dev, VE_DEC_MPEG_MP12HDR, reg);
108
109 /* Set frame dimensions. */
110
111 reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(seq->horizontal_size);
112 reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(seq->vertical_size);
113
114 cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg);
115
116 reg = VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(ctx->src_fmt.width);
117 reg |= VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(ctx->src_fmt.height);
118
119 cedrus_write(dev, VE_DEC_MPEG_PICBOUNDSIZE, reg);
120
121 /* Forward and backward prediction reference buffers. */
122 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
123
124 cedrus_write_ref_buf_addr(ctx, vq, pic->forward_ref_ts,
125 VE_DEC_MPEG_FWD_REF_LUMA_ADDR,
126 VE_DEC_MPEG_FWD_REF_CHROMA_ADDR);
127 cedrus_write_ref_buf_addr(ctx, vq, pic->backward_ref_ts,
128 VE_DEC_MPEG_BWD_REF_LUMA_ADDR,
129 VE_DEC_MPEG_BWD_REF_CHROMA_ADDR);
130
131 /* Destination luma and chroma buffers. */
132
133 dst_luma_addr = cedrus_dst_buf_addr(ctx, &run->dst->vb2_buf, 0);
134 dst_chroma_addr = cedrus_dst_buf_addr(ctx, &run->dst->vb2_buf, 1);
135
136 cedrus_write(dev, VE_DEC_MPEG_REC_LUMA, dst_luma_addr);
137 cedrus_write(dev, VE_DEC_MPEG_REC_CHROMA, dst_chroma_addr);
138
139 /* Source offset and length in bits. */
140
141 cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET, 0);
142
143 reg = vb2_get_plane_payload(&run->src->vb2_buf, 0) * 8;
144 cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg);
145
146 /* Source beginning and end addresses. */
147
148 src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
149
150 reg = VE_DEC_MPEG_VLD_ADDR_BASE(src_buf_addr);
151 reg |= VE_DEC_MPEG_VLD_ADDR_VALID_PIC_DATA;
152 reg |= VE_DEC_MPEG_VLD_ADDR_LAST_PIC_DATA;
153 reg |= VE_DEC_MPEG_VLD_ADDR_FIRST_PIC_DATA;
154
155 cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg);
156
157 reg = src_buf_addr + vb2_get_plane_payload(&run->src->vb2_buf, 0);
158 cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg);
159
160 /* Macroblock address: start at the beginning. */
161 reg = VE_DEC_MPEG_MBADDR_Y(0) | VE_DEC_MPEG_MBADDR_X(0);
162 cedrus_write(dev, VE_DEC_MPEG_MBADDR, reg);
163
164 /* Clear previous errors. */
165 cedrus_write(dev, VE_DEC_MPEG_ERROR, 0);
166
167 /* Clear correct macroblocks register. */
168 cedrus_write(dev, VE_DEC_MPEG_CRTMBADDR, 0);
169
170 /* Enable appropriate interruptions and components. */
171
172 reg = VE_DEC_MPEG_CTRL_IRQ_MASK | VE_DEC_MPEG_CTRL_MC_NO_WRITEBACK |
173 VE_DEC_MPEG_CTRL_MC_CACHE_EN;
174
175 cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
176
177 return 0;
178 }
179
cedrus_mpeg2_trigger(struct cedrus_ctx * ctx)180 static void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
181 {
182 struct cedrus_dev *dev = ctx->dev;
183 u32 reg;
184
185 /* Trigger MPEG engine. */
186 reg = VE_DEC_MPEG_TRIGGER_HW_MPEG_VLD | VE_DEC_MPEG_TRIGGER_MPEG2 |
187 VE_DEC_MPEG_TRIGGER_MB_BOUNDARY;
188
189 cedrus_write(dev, VE_DEC_MPEG_TRIGGER, reg);
190 }
191
192 struct cedrus_dec_ops cedrus_dec_ops_mpeg2 = {
193 .irq_clear = cedrus_mpeg2_irq_clear,
194 .irq_disable = cedrus_mpeg2_irq_disable,
195 .irq_status = cedrus_mpeg2_irq_status,
196 .setup = cedrus_mpeg2_setup,
197 .trigger = cedrus_mpeg2_trigger,
198 };
199