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 /* Default MPEG-2 quantization coefficients, from the specification. */
17 
18 static const u8 intra_quantization_matrix_default[64] = {
19 	8,  16, 16, 19, 16, 19, 22, 22,
20 	22, 22, 22, 22, 26, 24, 26, 27,
21 	27, 27, 26, 26, 26, 26, 27, 27,
22 	27, 29, 29, 29, 34, 34, 34, 29,
23 	29, 29, 27, 27, 29, 29, 32, 32,
24 	34, 34, 37, 38, 37, 35, 35, 34,
25 	35, 38, 38, 40, 40, 40, 48, 48,
26 	46, 46, 56, 56, 58, 69, 69, 83
27 };
28 
29 static const u8 non_intra_quantization_matrix_default[64] = {
30 	16, 16, 16, 16, 16, 16, 16, 16,
31 	16, 16, 16, 16, 16, 16, 16, 16,
32 	16, 16, 16, 16, 16, 16, 16, 16,
33 	16, 16, 16, 16, 16, 16, 16, 16,
34 	16, 16, 16, 16, 16, 16, 16, 16,
35 	16, 16, 16, 16, 16, 16, 16, 16,
36 	16, 16, 16, 16, 16, 16, 16, 16,
37 	16, 16, 16, 16, 16, 16, 16, 16
38 };
39 
40 static enum cedrus_irq_status cedrus_mpeg2_irq_status(struct cedrus_ctx *ctx)
41 {
42 	struct cedrus_dev *dev = ctx->dev;
43 	u32 reg;
44 
45 	reg = cedrus_read(dev, VE_DEC_MPEG_STATUS);
46 	reg &= VE_DEC_MPEG_STATUS_CHECK_MASK;
47 
48 	if (!reg)
49 		return CEDRUS_IRQ_NONE;
50 
51 	if (reg & VE_DEC_MPEG_STATUS_CHECK_ERROR ||
52 	    !(reg & VE_DEC_MPEG_STATUS_SUCCESS))
53 		return CEDRUS_IRQ_ERROR;
54 
55 	return CEDRUS_IRQ_OK;
56 }
57 
58 static void cedrus_mpeg2_irq_clear(struct cedrus_ctx *ctx)
59 {
60 	struct cedrus_dev *dev = ctx->dev;
61 
62 	cedrus_write(dev, VE_DEC_MPEG_STATUS, VE_DEC_MPEG_STATUS_CHECK_MASK);
63 }
64 
65 static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx)
66 {
67 	struct cedrus_dev *dev = ctx->dev;
68 	u32 reg = cedrus_read(dev, VE_DEC_MPEG_CTRL);
69 
70 	reg &= ~VE_DEC_MPEG_CTRL_IRQ_MASK;
71 
72 	cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
73 }
74 
75 static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
76 {
77 	const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
78 	const struct v4l2_mpeg2_sequence *sequence;
79 	const struct v4l2_mpeg2_picture *picture;
80 	const struct v4l2_ctrl_mpeg2_quantization *quantization;
81 	dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
82 	dma_addr_t fwd_luma_addr, fwd_chroma_addr;
83 	dma_addr_t bwd_luma_addr, bwd_chroma_addr;
84 	struct cedrus_dev *dev = ctx->dev;
85 	struct vb2_queue *vq;
86 	const u8 *matrix;
87 	int forward_idx;
88 	int backward_idx;
89 	unsigned int i;
90 	u32 reg;
91 
92 	slice_params = run->mpeg2.slice_params;
93 	sequence = &slice_params->sequence;
94 	picture = &slice_params->picture;
95 
96 	quantization = run->mpeg2.quantization;
97 
98 	/* Activate MPEG engine. */
99 	cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2);
100 
101 	/* Set intra quantization matrix. */
102 
103 	if (quantization && quantization->load_intra_quantiser_matrix)
104 		matrix = quantization->intra_quantiser_matrix;
105 	else
106 		matrix = intra_quantization_matrix_default;
107 
108 	for (i = 0; i < 64; i++) {
109 		reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
110 		reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA;
111 
112 		cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
113 	}
114 
115 	/* Set non-intra quantization matrix. */
116 
117 	if (quantization && quantization->load_non_intra_quantiser_matrix)
118 		matrix = quantization->non_intra_quantiser_matrix;
119 	else
120 		matrix = non_intra_quantization_matrix_default;
121 
122 	for (i = 0; i < 64; i++) {
123 		reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
124 		reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA;
125 
126 		cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
127 	}
128 
129 	/* Set MPEG picture header. */
130 
131 	reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(picture->picture_coding_type);
132 	reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, picture->f_code[0][0]);
133 	reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, picture->f_code[0][1]);
134 	reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, picture->f_code[1][0]);
135 	reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, picture->f_code[1][1]);
136 	reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(picture->intra_dc_precision);
137 	reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(picture->picture_structure);
138 	reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(picture->top_field_first);
139 	reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(picture->frame_pred_frame_dct);
140 	reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(picture->concealment_motion_vectors);
141 	reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(picture->q_scale_type);
142 	reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(picture->intra_vlc_format);
143 	reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(picture->alternate_scan);
144 	reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0);
145 	reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0);
146 
147 	cedrus_write(dev, VE_DEC_MPEG_MP12HDR, reg);
148 
149 	/* Set frame dimensions. */
150 
151 	reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(sequence->horizontal_size);
152 	reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(sequence->vertical_size);
153 
154 	cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg);
155 
156 	reg = VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(ctx->src_fmt.width);
157 	reg |= VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(ctx->src_fmt.height);
158 
159 	cedrus_write(dev, VE_DEC_MPEG_PICBOUNDSIZE, reg);
160 
161 	/* Forward and backward prediction reference buffers. */
162 
163 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
164 
165 	forward_idx = vb2_find_timestamp(vq, slice_params->forward_ref_ts, 0);
166 	fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0);
167 	fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1);
168 
169 	cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr);
170 	cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr);
171 
172 	backward_idx = vb2_find_timestamp(vq, slice_params->backward_ref_ts, 0);
173 	bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0);
174 	bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1);
175 
176 	cedrus_write(dev, VE_DEC_MPEG_BWD_REF_LUMA_ADDR, bwd_luma_addr);
177 	cedrus_write(dev, VE_DEC_MPEG_BWD_REF_CHROMA_ADDR, bwd_chroma_addr);
178 
179 	/* Destination luma and chroma buffers. */
180 
181 	dst_luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0);
182 	dst_chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1);
183 
184 	cedrus_write(dev, VE_DEC_MPEG_REC_LUMA, dst_luma_addr);
185 	cedrus_write(dev, VE_DEC_MPEG_REC_CHROMA, dst_chroma_addr);
186 
187 	/* Source offset and length in bits. */
188 
189 	cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET,
190 		     slice_params->data_bit_offset);
191 
192 	reg = slice_params->bit_size - slice_params->data_bit_offset;
193 	cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg);
194 
195 	/* Source beginning and end addresses. */
196 
197 	src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
198 
199 	reg = VE_DEC_MPEG_VLD_ADDR_BASE(src_buf_addr);
200 	reg |= VE_DEC_MPEG_VLD_ADDR_VALID_PIC_DATA;
201 	reg |= VE_DEC_MPEG_VLD_ADDR_LAST_PIC_DATA;
202 	reg |= VE_DEC_MPEG_VLD_ADDR_FIRST_PIC_DATA;
203 
204 	cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg);
205 
206 	reg = src_buf_addr + DIV_ROUND_UP(slice_params->bit_size, 8);
207 	cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg);
208 
209 	/* Macroblock address: start at the beginning. */
210 	reg = VE_DEC_MPEG_MBADDR_Y(0) | VE_DEC_MPEG_MBADDR_X(0);
211 	cedrus_write(dev, VE_DEC_MPEG_MBADDR, reg);
212 
213 	/* Clear previous errors. */
214 	cedrus_write(dev, VE_DEC_MPEG_ERROR, 0);
215 
216 	/* Clear correct macroblocks register. */
217 	cedrus_write(dev, VE_DEC_MPEG_CRTMBADDR, 0);
218 
219 	/* Enable appropriate interruptions and components. */
220 
221 	reg = VE_DEC_MPEG_CTRL_IRQ_MASK | VE_DEC_MPEG_CTRL_MC_NO_WRITEBACK |
222 	      VE_DEC_MPEG_CTRL_MC_CACHE_EN;
223 
224 	cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
225 }
226 
227 static void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
228 {
229 	struct cedrus_dev *dev = ctx->dev;
230 	u32 reg;
231 
232 	/* Trigger MPEG engine. */
233 	reg = VE_DEC_MPEG_TRIGGER_HW_MPEG_VLD | VE_DEC_MPEG_TRIGGER_MPEG2 |
234 	      VE_DEC_MPEG_TRIGGER_MB_BOUNDARY;
235 
236 	cedrus_write(dev, VE_DEC_MPEG_TRIGGER, reg);
237 }
238 
239 struct cedrus_dec_ops cedrus_dec_ops_mpeg2 = {
240 	.irq_clear	= cedrus_mpeg2_irq_clear,
241 	.irq_disable	= cedrus_mpeg2_irq_disable,
242 	.irq_status	= cedrus_mpeg2_irq_status,
243 	.setup		= cedrus_mpeg2_setup,
244 	.trigger	= cedrus_mpeg2_trigger,
245 };
246