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 | |
28 | static void imx8m_soft_reset(struct hantro_dev *vpu, u32 reset_bits) |
29 | { |
30 | u32 val; |
31 | |
32 | /* Assert */ |
33 | val = readl(addr: vpu->ctrl_base + CTRL_SOFT_RESET); |
34 | val &= ~reset_bits; |
35 | writel(val, addr: vpu->ctrl_base + CTRL_SOFT_RESET); |
36 | |
37 | udelay(2); |
38 | |
39 | /* Release */ |
40 | val = readl(addr: vpu->ctrl_base + CTRL_SOFT_RESET); |
41 | val |= reset_bits; |
42 | writel(val, addr: vpu->ctrl_base + CTRL_SOFT_RESET); |
43 | } |
44 | |
45 | static void imx8m_clk_enable(struct hantro_dev *vpu, u32 clock_bits) |
46 | { |
47 | u32 val; |
48 | |
49 | val = readl(addr: vpu->ctrl_base + CTRL_CLOCK_ENABLE); |
50 | val |= clock_bits; |
51 | writel(val, addr: vpu->ctrl_base + CTRL_CLOCK_ENABLE); |
52 | } |
53 | |
54 | static int imx8mq_runtime_resume(struct hantro_dev *vpu) |
55 | { |
56 | int ret; |
57 | |
58 | ret = clk_bulk_prepare_enable(num_clks: vpu->variant->num_clocks, clks: 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(val: 0xffffffff, addr: vpu->ctrl_base + CTRL_G1_DEC_FUSE); |
69 | writel(val: 0xffffffff, addr: vpu->ctrl_base + CTRL_G1_PP_FUSE); |
70 | writel(val: 0xffffffff, addr: vpu->ctrl_base + CTRL_G2_DEC_FUSE); |
71 | |
72 | clk_bulk_disable_unprepare(num_clks: vpu->variant->num_clocks, clks: vpu->clocks); |
73 | |
74 | return 0; |
75 | } |
76 | |
77 | /* |
78 | * Supported formats. |
79 | */ |
80 | |
81 | static const struct hantro_fmt imx8m_vpu_postproc_fmts[] = { |
82 | { |
83 | .fourcc = V4L2_PIX_FMT_YUYV, |
84 | .codec_mode = HANTRO_MODE_NONE, |
85 | .postprocessed = true, |
86 | .frmsize = { |
87 | .min_width = FMT_MIN_WIDTH, |
88 | .max_width = FMT_UHD_WIDTH, |
89 | .step_width = MB_DIM, |
90 | .min_height = FMT_MIN_HEIGHT, |
91 | .max_height = FMT_UHD_HEIGHT, |
92 | .step_height = MB_DIM, |
93 | }, |
94 | }, |
95 | }; |
96 | |
97 | static const struct hantro_fmt imx8m_vpu_dec_fmts[] = { |
98 | { |
99 | .fourcc = V4L2_PIX_FMT_NV12, |
100 | .codec_mode = HANTRO_MODE_NONE, |
101 | .frmsize = { |
102 | .min_width = FMT_MIN_WIDTH, |
103 | .max_width = FMT_UHD_WIDTH, |
104 | .step_width = MB_DIM, |
105 | .min_height = FMT_MIN_HEIGHT, |
106 | .max_height = FMT_UHD_HEIGHT, |
107 | .step_height = MB_DIM, |
108 | }, |
109 | }, |
110 | { |
111 | .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, |
112 | .codec_mode = HANTRO_MODE_MPEG2_DEC, |
113 | .max_depth = 2, |
114 | .frmsize = { |
115 | .min_width = FMT_MIN_WIDTH, |
116 | .max_width = FMT_FHD_WIDTH, |
117 | .step_width = MB_DIM, |
118 | .min_height = FMT_MIN_HEIGHT, |
119 | .max_height = FMT_FHD_HEIGHT, |
120 | .step_height = MB_DIM, |
121 | }, |
122 | }, |
123 | { |
124 | .fourcc = V4L2_PIX_FMT_VP8_FRAME, |
125 | .codec_mode = HANTRO_MODE_VP8_DEC, |
126 | .max_depth = 2, |
127 | .frmsize = { |
128 | .min_width = FMT_MIN_WIDTH, |
129 | .max_width = FMT_UHD_WIDTH, |
130 | .step_width = MB_DIM, |
131 | .min_height = FMT_MIN_HEIGHT, |
132 | .max_height = FMT_UHD_HEIGHT, |
133 | .step_height = MB_DIM, |
134 | }, |
135 | }, |
136 | { |
137 | .fourcc = V4L2_PIX_FMT_H264_SLICE, |
138 | .codec_mode = HANTRO_MODE_H264_DEC, |
139 | .max_depth = 2, |
140 | .frmsize = { |
141 | .min_width = FMT_MIN_WIDTH, |
142 | .max_width = FMT_UHD_WIDTH, |
143 | .step_width = MB_DIM, |
144 | .min_height = FMT_MIN_HEIGHT, |
145 | .max_height = FMT_UHD_HEIGHT, |
146 | .step_height = MB_DIM, |
147 | }, |
148 | }, |
149 | }; |
150 | |
151 | static const struct hantro_fmt imx8m_vpu_g2_postproc_fmts[] = { |
152 | { |
153 | .fourcc = V4L2_PIX_FMT_NV12, |
154 | .codec_mode = HANTRO_MODE_NONE, |
155 | .match_depth = true, |
156 | .postprocessed = true, |
157 | .frmsize = { |
158 | .min_width = FMT_MIN_WIDTH, |
159 | .max_width = FMT_UHD_WIDTH, |
160 | .step_width = MB_DIM, |
161 | .min_height = FMT_MIN_HEIGHT, |
162 | .max_height = FMT_UHD_HEIGHT, |
163 | .step_height = MB_DIM, |
164 | }, |
165 | }, |
166 | { |
167 | .fourcc = V4L2_PIX_FMT_P010, |
168 | .codec_mode = HANTRO_MODE_NONE, |
169 | .match_depth = true, |
170 | .postprocessed = true, |
171 | .frmsize = { |
172 | .min_width = FMT_MIN_WIDTH, |
173 | .max_width = FMT_UHD_WIDTH, |
174 | .step_width = MB_DIM, |
175 | .min_height = FMT_MIN_HEIGHT, |
176 | .max_height = FMT_UHD_HEIGHT, |
177 | .step_height = MB_DIM, |
178 | }, |
179 | }, |
180 | }; |
181 | |
182 | static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { |
183 | { |
184 | .fourcc = V4L2_PIX_FMT_NV12_4L4, |
185 | .codec_mode = HANTRO_MODE_NONE, |
186 | .match_depth = true, |
187 | .frmsize = { |
188 | .min_width = FMT_MIN_WIDTH, |
189 | .max_width = FMT_UHD_WIDTH, |
190 | .step_width = TILE_MB_DIM, |
191 | .min_height = FMT_MIN_HEIGHT, |
192 | .max_height = FMT_UHD_HEIGHT, |
193 | .step_height = TILE_MB_DIM, |
194 | }, |
195 | }, |
196 | { |
197 | .fourcc = V4L2_PIX_FMT_P010_4L4, |
198 | .codec_mode = HANTRO_MODE_NONE, |
199 | .match_depth = true, |
200 | .frmsize = { |
201 | .min_width = FMT_MIN_WIDTH, |
202 | .max_width = FMT_UHD_WIDTH, |
203 | .step_width = TILE_MB_DIM, |
204 | .min_height = FMT_MIN_HEIGHT, |
205 | .max_height = FMT_UHD_HEIGHT, |
206 | .step_height = TILE_MB_DIM, |
207 | }, |
208 | }, |
209 | { |
210 | .fourcc = V4L2_PIX_FMT_HEVC_SLICE, |
211 | .codec_mode = HANTRO_MODE_HEVC_DEC, |
212 | .max_depth = 2, |
213 | .frmsize = { |
214 | .min_width = FMT_MIN_WIDTH, |
215 | .max_width = FMT_UHD_WIDTH, |
216 | .step_width = TILE_MB_DIM, |
217 | .min_height = FMT_MIN_HEIGHT, |
218 | .max_height = FMT_UHD_HEIGHT, |
219 | .step_height = TILE_MB_DIM, |
220 | }, |
221 | }, |
222 | { |
223 | .fourcc = V4L2_PIX_FMT_VP9_FRAME, |
224 | .codec_mode = HANTRO_MODE_VP9_DEC, |
225 | .max_depth = 2, |
226 | .frmsize = { |
227 | .min_width = FMT_MIN_WIDTH, |
228 | .max_width = FMT_UHD_WIDTH, |
229 | .step_width = TILE_MB_DIM, |
230 | .min_height = FMT_MIN_HEIGHT, |
231 | .max_height = FMT_UHD_HEIGHT, |
232 | .step_height = TILE_MB_DIM, |
233 | }, |
234 | }, |
235 | }; |
236 | |
237 | static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) |
238 | { |
239 | struct hantro_dev *vpu = dev_id; |
240 | enum vb2_buffer_state state; |
241 | u32 status; |
242 | |
243 | status = vdpu_read(vpu, G1_REG_INTERRUPT); |
244 | state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ? |
245 | VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; |
246 | |
247 | vdpu_write(vpu, val: 0, G1_REG_INTERRUPT); |
248 | vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); |
249 | |
250 | hantro_irq_done(vpu, result: state); |
251 | |
252 | return IRQ_HANDLED; |
253 | } |
254 | |
255 | static int imx8mq_vpu_hw_init(struct hantro_dev *vpu) |
256 | { |
257 | vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1]; |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx) |
263 | { |
264 | struct hantro_dev *vpu = ctx->dev; |
265 | |
266 | imx8m_soft_reset(vpu, RESET_G1); |
267 | } |
268 | |
269 | /* |
270 | * Supported codec ops. |
271 | */ |
272 | |
273 | static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = { |
274 | [HANTRO_MODE_MPEG2_DEC] = { |
275 | .run = hantro_g1_mpeg2_dec_run, |
276 | .reset = imx8m_vpu_g1_reset, |
277 | .init = hantro_mpeg2_dec_init, |
278 | .exit = hantro_mpeg2_dec_exit, |
279 | }, |
280 | [HANTRO_MODE_VP8_DEC] = { |
281 | .run = hantro_g1_vp8_dec_run, |
282 | .reset = imx8m_vpu_g1_reset, |
283 | .init = hantro_vp8_dec_init, |
284 | .exit = hantro_vp8_dec_exit, |
285 | }, |
286 | [HANTRO_MODE_H264_DEC] = { |
287 | .run = hantro_g1_h264_dec_run, |
288 | .reset = imx8m_vpu_g1_reset, |
289 | .init = hantro_h264_dec_init, |
290 | .exit = hantro_h264_dec_exit, |
291 | }, |
292 | }; |
293 | |
294 | static const struct hantro_codec_ops imx8mq_vpu_g1_codec_ops[] = { |
295 | [HANTRO_MODE_MPEG2_DEC] = { |
296 | .run = hantro_g1_mpeg2_dec_run, |
297 | .init = hantro_mpeg2_dec_init, |
298 | .exit = hantro_mpeg2_dec_exit, |
299 | }, |
300 | [HANTRO_MODE_VP8_DEC] = { |
301 | .run = hantro_g1_vp8_dec_run, |
302 | .init = hantro_vp8_dec_init, |
303 | .exit = hantro_vp8_dec_exit, |
304 | }, |
305 | [HANTRO_MODE_H264_DEC] = { |
306 | .run = hantro_g1_h264_dec_run, |
307 | .init = hantro_h264_dec_init, |
308 | .exit = hantro_h264_dec_exit, |
309 | }, |
310 | }; |
311 | |
312 | static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { |
313 | [HANTRO_MODE_HEVC_DEC] = { |
314 | .run = hantro_g2_hevc_dec_run, |
315 | .init = hantro_hevc_dec_init, |
316 | .exit = hantro_hevc_dec_exit, |
317 | }, |
318 | [HANTRO_MODE_VP9_DEC] = { |
319 | .run = hantro_g2_vp9_dec_run, |
320 | .done = hantro_g2_vp9_dec_done, |
321 | .init = hantro_vp9_dec_init, |
322 | .exit = hantro_vp9_dec_exit, |
323 | }, |
324 | }; |
325 | |
326 | /* |
327 | * VPU variants. |
328 | */ |
329 | |
330 | static const struct hantro_irq imx8mq_irqs[] = { |
331 | { "g1" , imx8m_vpu_g1_irq }, |
332 | }; |
333 | |
334 | static const struct hantro_irq imx8mq_g2_irqs[] = { |
335 | { "g2" , hantro_g2_irq }, |
336 | }; |
337 | |
338 | static const char * const imx8mq_clk_names[] = { "g1" , "g2" , "bus" }; |
339 | static const char * const imx8mq_reg_names[] = { "g1" , "g2" , "ctrl" }; |
340 | static const char * const imx8mq_g1_clk_names[] = { "g1" }; |
341 | static const char * const imx8mq_g2_clk_names[] = { "g2" }; |
342 | |
343 | const struct hantro_variant imx8mq_vpu_variant = { |
344 | .dec_fmts = imx8m_vpu_dec_fmts, |
345 | .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts), |
346 | .postproc_fmts = imx8m_vpu_postproc_fmts, |
347 | .num_postproc_fmts = ARRAY_SIZE(imx8m_vpu_postproc_fmts), |
348 | .postproc_ops = &hantro_g1_postproc_ops, |
349 | .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | |
350 | HANTRO_H264_DECODER, |
351 | .codec_ops = imx8mq_vpu_codec_ops, |
352 | .init = imx8mq_vpu_hw_init, |
353 | .runtime_resume = imx8mq_runtime_resume, |
354 | .irqs = imx8mq_irqs, |
355 | .num_irqs = ARRAY_SIZE(imx8mq_irqs), |
356 | .clk_names = imx8mq_clk_names, |
357 | .num_clocks = ARRAY_SIZE(imx8mq_clk_names), |
358 | .reg_names = imx8mq_reg_names, |
359 | .num_regs = ARRAY_SIZE(imx8mq_reg_names) |
360 | }; |
361 | |
362 | const struct hantro_variant imx8mq_vpu_g1_variant = { |
363 | .dec_fmts = imx8m_vpu_dec_fmts, |
364 | .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts), |
365 | .postproc_fmts = imx8m_vpu_postproc_fmts, |
366 | .num_postproc_fmts = ARRAY_SIZE(imx8m_vpu_postproc_fmts), |
367 | .postproc_ops = &hantro_g1_postproc_ops, |
368 | .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | |
369 | HANTRO_H264_DECODER, |
370 | .codec_ops = imx8mq_vpu_g1_codec_ops, |
371 | .irqs = imx8mq_irqs, |
372 | .num_irqs = ARRAY_SIZE(imx8mq_irqs), |
373 | .clk_names = imx8mq_g1_clk_names, |
374 | .num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names), |
375 | }; |
376 | |
377 | const struct hantro_variant imx8mq_vpu_g2_variant = { |
378 | .dec_offset = 0x0, |
379 | .dec_fmts = imx8m_vpu_g2_dec_fmts, |
380 | .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_g2_dec_fmts), |
381 | .postproc_fmts = imx8m_vpu_g2_postproc_fmts, |
382 | .num_postproc_fmts = ARRAY_SIZE(imx8m_vpu_g2_postproc_fmts), |
383 | .postproc_ops = &hantro_g2_postproc_ops, |
384 | .codec = HANTRO_HEVC_DECODER | HANTRO_VP9_DECODER, |
385 | .codec_ops = imx8mq_vpu_g2_codec_ops, |
386 | .irqs = imx8mq_g2_irqs, |
387 | .num_irqs = ARRAY_SIZE(imx8mq_g2_irqs), |
388 | .clk_names = imx8mq_g2_clk_names, |
389 | .num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names), |
390 | }; |
391 | |
392 | const struct hantro_variant imx8mm_vpu_g1_variant = { |
393 | .dec_fmts = imx8m_vpu_dec_fmts, |
394 | .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts), |
395 | .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | |
396 | HANTRO_H264_DECODER, |
397 | .codec_ops = imx8mq_vpu_g1_codec_ops, |
398 | .irqs = imx8mq_irqs, |
399 | .num_irqs = ARRAY_SIZE(imx8mq_irqs), |
400 | .clk_names = imx8mq_g1_clk_names, |
401 | .num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names), |
402 | }; |
403 | |