Commit | Line | Data |
---|---|---|
3d107833 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
cd6c56fe DO |
2 | /* |
3 | * NVIDIA Tegra Video decoder driver | |
4 | * | |
5 | * Copyright (C) 2016-2017 Dmitry Osipenko <digetx@gmail.com> | |
6 | * | |
cd6c56fe DO |
7 | */ |
8 | ||
9 | #include <linux/clk.h> | |
10 | #include <linux/dma-buf.h> | |
11 | #include <linux/genalloc.h> | |
12 | #include <linux/interrupt.h> | |
13 | #include <linux/iopoll.h> | |
92cd1440 | 14 | #include <linux/list.h> |
cd6c56fe DO |
15 | #include <linux/miscdevice.h> |
16 | #include <linux/module.h> | |
7f951cb8 | 17 | #include <linux/of_device.h> |
cd6c56fe DO |
18 | #include <linux/pm_runtime.h> |
19 | #include <linux/reset.h> | |
20 | #include <linux/slab.h> | |
21 | #include <linux/uaccess.h> | |
22 | ||
23 | #include <soc/tegra/pmc.h> | |
24 | ||
25 | #include "uapi.h" | |
b301f8de DO |
26 | #include "vde.h" |
27 | ||
28 | #define CREATE_TRACE_POINTS | |
29 | #include "trace.h" | |
cd6c56fe DO |
30 | |
31 | #define ICMDQUE_WR 0x00 | |
32 | #define CMDQUE_CONTROL 0x08 | |
33 | #define INTR_STATUS 0x18 | |
34 | #define BSE_INT_ENB 0x40 | |
35 | #define BSE_CONFIG 0x44 | |
36 | ||
37 | #define BSE_ICMDQUE_EMPTY BIT(3) | |
38 | #define BSE_DMA_BUSY BIT(23) | |
39 | ||
cd6c56fe DO |
40 | struct video_frame { |
41 | struct dma_buf_attachment *y_dmabuf_attachment; | |
42 | struct dma_buf_attachment *cb_dmabuf_attachment; | |
43 | struct dma_buf_attachment *cr_dmabuf_attachment; | |
44 | struct dma_buf_attachment *aux_dmabuf_attachment; | |
cd6c56fe DO |
45 | dma_addr_t y_addr; |
46 | dma_addr_t cb_addr; | |
47 | dma_addr_t cr_addr; | |
48 | dma_addr_t aux_addr; | |
49 | u32 frame_num; | |
50 | u32 flags; | |
51 | }; | |
52 | ||
91dc5e91 DO |
53 | static void tegra_vde_writel(struct tegra_vde *vde, |
54 | u32 value, void __iomem *base, u32 offset) | |
55 | { | |
56 | trace_vde_writel(vde, base, offset, value); | |
57 | ||
58 | writel_relaxed(value, base + offset); | |
59 | } | |
60 | ||
61 | static u32 tegra_vde_readl(struct tegra_vde *vde, | |
62 | void __iomem *base, u32 offset) | |
63 | { | |
64 | u32 value = readl_relaxed(base + offset); | |
65 | ||
66 | trace_vde_readl(vde, base, offset, value); | |
67 | ||
68 | return value; | |
69 | } | |
70 | ||
cd6c56fe | 71 | static void tegra_vde_set_bits(struct tegra_vde *vde, |
91dc5e91 | 72 | u32 mask, void __iomem *base, u32 offset) |
cd6c56fe | 73 | { |
91dc5e91 | 74 | u32 value = tegra_vde_readl(vde, base, offset); |
cd6c56fe | 75 | |
91dc5e91 | 76 | tegra_vde_writel(vde, value | mask, base, offset); |
cd6c56fe DO |
77 | } |
78 | ||
79 | static int tegra_vde_wait_mbe(struct tegra_vde *vde) | |
80 | { | |
81 | u32 tmp; | |
82 | ||
83 | return readl_relaxed_poll_timeout(vde->mbe + 0x8C, tmp, | |
84 | (tmp >= 0x10), 1, 100); | |
85 | } | |
86 | ||
87 | static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde, | |
88 | unsigned int refs_nb, | |
89 | bool setup_refs) | |
90 | { | |
91 | u32 frame_idx_enb_mask = 0; | |
92 | u32 value; | |
93 | unsigned int frame_idx; | |
94 | unsigned int idx; | |
95 | int err; | |
96 | ||
91dc5e91 DO |
97 | tegra_vde_writel(vde, 0xD0000000 | (0 << 23), vde->mbe, 0x80); |
98 | tegra_vde_writel(vde, 0xD0200000 | (0 << 23), vde->mbe, 0x80); | |
cd6c56fe DO |
99 | |
100 | err = tegra_vde_wait_mbe(vde); | |
101 | if (err) | |
102 | return err; | |
103 | ||
104 | if (!setup_refs) | |
105 | return 0; | |
106 | ||
107 | for (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) { | |
91dc5e91 DO |
108 | tegra_vde_writel(vde, 0xD0000000 | (frame_idx << 23), |
109 | vde->mbe, 0x80); | |
110 | tegra_vde_writel(vde, 0xD0200000 | (frame_idx << 23), | |
111 | vde->mbe, 0x80); | |
cd6c56fe DO |
112 | |
113 | frame_idx_enb_mask |= frame_idx << (6 * (idx % 4)); | |
114 | ||
115 | if (idx % 4 == 3 || idx == refs_nb - 1) { | |
116 | value = 0xC0000000; | |
117 | value |= (idx >> 2) << 24; | |
118 | value |= frame_idx_enb_mask; | |
119 | ||
91dc5e91 | 120 | tegra_vde_writel(vde, value, vde->mbe, 0x80); |
cd6c56fe DO |
121 | |
122 | err = tegra_vde_wait_mbe(vde); | |
123 | if (err) | |
124 | return err; | |
125 | ||
126 | frame_idx_enb_mask = 0; | |
127 | } | |
128 | } | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
133 | static void tegra_vde_mbe_set_0xa_reg(struct tegra_vde *vde, int reg, u32 val) | |
134 | { | |
91dc5e91 DO |
135 | tegra_vde_writel(vde, 0xA0000000 | (reg << 24) | (val & 0xFFFF), |
136 | vde->mbe, 0x80); | |
137 | tegra_vde_writel(vde, 0xA0000000 | ((reg + 1) << 24) | (val >> 16), | |
138 | vde->mbe, 0x80); | |
cd6c56fe DO |
139 | } |
140 | ||
141 | static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma) | |
142 | { | |
143 | struct device *dev = vde->miscdev.parent; | |
144 | u32 value; | |
145 | int err; | |
146 | ||
147 | err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, | |
148 | !(value & BIT(2)), 1, 100); | |
149 | if (err) { | |
150 | dev_err(dev, "BSEV unknown bit timeout\n"); | |
151 | return err; | |
152 | } | |
153 | ||
154 | err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, | |
155 | (value & BSE_ICMDQUE_EMPTY), 1, 100); | |
156 | if (err) { | |
157 | dev_err(dev, "BSEV ICMDQUE flush timeout\n"); | |
158 | return err; | |
159 | } | |
160 | ||
161 | if (!wait_dma) | |
162 | return 0; | |
163 | ||
164 | err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, | |
165 | !(value & BSE_DMA_BUSY), 1, 100); | |
166 | if (err) { | |
167 | dev_err(dev, "BSEV DMA timeout\n"); | |
168 | return err; | |
169 | } | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | static int tegra_vde_push_to_bsev_icmdqueue(struct tegra_vde *vde, | |
175 | u32 value, bool wait_dma) | |
176 | { | |
91dc5e91 | 177 | tegra_vde_writel(vde, value, vde->bsev, ICMDQUE_WR); |
cd6c56fe DO |
178 | |
179 | return tegra_vde_wait_bsev(vde, wait_dma); | |
180 | } | |
181 | ||
182 | static void tegra_vde_setup_frameid(struct tegra_vde *vde, | |
183 | struct video_frame *frame, | |
184 | unsigned int frameid, | |
185 | u32 mbs_width, u32 mbs_height) | |
186 | { | |
187 | u32 y_addr = frame ? frame->y_addr : 0x6CDEAD00; | |
188 | u32 cb_addr = frame ? frame->cb_addr : 0x6CDEAD00; | |
189 | u32 cr_addr = frame ? frame->cr_addr : 0x6CDEAD00; | |
190 | u32 value1 = frame ? ((mbs_width << 16) | mbs_height) : 0; | |
191 | u32 value2 = frame ? ((((mbs_width + 1) >> 1) << 6) | 1) : 0; | |
192 | ||
91dc5e91 DO |
193 | tegra_vde_writel(vde, y_addr >> 8, vde->frameid, 0x000 + frameid * 4); |
194 | tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4); | |
195 | tegra_vde_writel(vde, cr_addr >> 8, vde->frameid, 0x180 + frameid * 4); | |
196 | tegra_vde_writel(vde, value1, vde->frameid, 0x080 + frameid * 4); | |
197 | tegra_vde_writel(vde, value2, vde->frameid, 0x280 + frameid * 4); | |
cd6c56fe DO |
198 | } |
199 | ||
200 | static void tegra_setup_frameidx(struct tegra_vde *vde, | |
201 | struct video_frame *frames, | |
202 | unsigned int frames_nb, | |
203 | u32 mbs_width, u32 mbs_height) | |
204 | { | |
205 | unsigned int idx; | |
206 | ||
207 | for (idx = 0; idx < frames_nb; idx++) | |
208 | tegra_vde_setup_frameid(vde, &frames[idx], idx, | |
209 | mbs_width, mbs_height); | |
210 | ||
211 | for (; idx < 17; idx++) | |
212 | tegra_vde_setup_frameid(vde, NULL, idx, 0, 0); | |
213 | } | |
214 | ||
215 | static void tegra_vde_setup_iram_entry(struct tegra_vde *vde, | |
216 | unsigned int table, | |
217 | unsigned int row, | |
218 | u32 value1, u32 value2) | |
219 | { | |
220 | u32 *iram_tables = vde->iram; | |
221 | ||
91dc5e91 | 222 | trace_vde_setup_iram_entry(table, row, value1, value2); |
cd6c56fe DO |
223 | |
224 | iram_tables[0x20 * table + row * 2] = value1; | |
225 | iram_tables[0x20 * table + row * 2 + 1] = value2; | |
226 | } | |
227 | ||
228 | static void tegra_vde_setup_iram_tables(struct tegra_vde *vde, | |
229 | struct video_frame *dpb_frames, | |
230 | unsigned int ref_frames_nb, | |
231 | unsigned int with_earlier_poc_nb) | |
232 | { | |
233 | struct video_frame *frame; | |
234 | u32 value, aux_addr; | |
235 | int with_later_poc_nb; | |
236 | unsigned int i, k; | |
237 | ||
91dc5e91 | 238 | trace_vde_ref_l0(dpb_frames[0].frame_num); |
cd6c56fe DO |
239 | |
240 | for (i = 0; i < 16; i++) { | |
241 | if (i < ref_frames_nb) { | |
242 | frame = &dpb_frames[i + 1]; | |
243 | ||
244 | aux_addr = frame->aux_addr; | |
245 | ||
246 | value = (i + 1) << 26; | |
247 | value |= !(frame->flags & FLAG_B_FRAME) << 25; | |
248 | value |= 1 << 24; | |
249 | value |= frame->frame_num; | |
cd6c56fe DO |
250 | } else { |
251 | aux_addr = 0x6ADEAD00; | |
252 | value = 0; | |
253 | } | |
254 | ||
255 | tegra_vde_setup_iram_entry(vde, 0, i, value, aux_addr); | |
256 | tegra_vde_setup_iram_entry(vde, 1, i, value, aux_addr); | |
257 | tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); | |
258 | tegra_vde_setup_iram_entry(vde, 3, i, value, aux_addr); | |
259 | } | |
260 | ||
261 | if (!(dpb_frames[0].flags & FLAG_B_FRAME)) | |
262 | return; | |
263 | ||
264 | if (with_earlier_poc_nb >= ref_frames_nb) | |
265 | return; | |
266 | ||
267 | with_later_poc_nb = ref_frames_nb - with_earlier_poc_nb; | |
268 | ||
91dc5e91 | 269 | trace_vde_ref_l1(with_later_poc_nb, with_earlier_poc_nb); |
cd6c56fe DO |
270 | |
271 | for (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) { | |
272 | frame = &dpb_frames[k + 1]; | |
273 | ||
274 | aux_addr = frame->aux_addr; | |
275 | ||
276 | value = (k + 1) << 26; | |
277 | value |= !(frame->flags & FLAG_B_FRAME) << 25; | |
278 | value |= 1 << 24; | |
279 | value |= frame->frame_num; | |
280 | ||
cd6c56fe DO |
281 | tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); |
282 | } | |
283 | ||
284 | for (k = 0; i < ref_frames_nb; i++, k++) { | |
285 | frame = &dpb_frames[k + 1]; | |
286 | ||
287 | aux_addr = frame->aux_addr; | |
288 | ||
289 | value = (k + 1) << 26; | |
290 | value |= !(frame->flags & FLAG_B_FRAME) << 25; | |
291 | value |= 1 << 24; | |
292 | value |= frame->frame_num; | |
293 | ||
cd6c56fe DO |
294 | tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); |
295 | } | |
296 | } | |
297 | ||
298 | static int tegra_vde_setup_hw_context(struct tegra_vde *vde, | |
299 | struct tegra_vde_h264_decoder_ctx *ctx, | |
300 | struct video_frame *dpb_frames, | |
301 | dma_addr_t bitstream_data_addr, | |
302 | size_t bitstream_data_size, | |
303 | unsigned int macroblocks_nb) | |
304 | { | |
305 | struct device *dev = vde->miscdev.parent; | |
306 | u32 value; | |
307 | int err; | |
308 | ||
91dc5e91 DO |
309 | tegra_vde_set_bits(vde, 0x000A, vde->sxe, 0xF0); |
310 | tegra_vde_set_bits(vde, 0x000B, vde->bsev, CMDQUE_CONTROL); | |
311 | tegra_vde_set_bits(vde, 0x8002, vde->mbe, 0x50); | |
312 | tegra_vde_set_bits(vde, 0x000A, vde->mbe, 0xA0); | |
313 | tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x14); | |
314 | tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x28); | |
315 | tegra_vde_set_bits(vde, 0x0A00, vde->mce, 0x08); | |
316 | tegra_vde_set_bits(vde, 0x000A, vde->tfe, 0x00); | |
317 | tegra_vde_set_bits(vde, 0x0005, vde->vdma, 0x04); | |
318 | ||
319 | tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x1C); | |
320 | tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x00); | |
321 | tegra_vde_writel(vde, 0x00000007, vde->vdma, 0x04); | |
322 | tegra_vde_writel(vde, 0x00000007, vde->frameid, 0x200); | |
323 | tegra_vde_writel(vde, 0x00000005, vde->tfe, 0x04); | |
324 | tegra_vde_writel(vde, 0x00000000, vde->mbe, 0x84); | |
325 | tegra_vde_writel(vde, 0x00000010, vde->sxe, 0x08); | |
326 | tegra_vde_writel(vde, 0x00000150, vde->sxe, 0x54); | |
327 | tegra_vde_writel(vde, 0x0000054C, vde->sxe, 0x58); | |
328 | tegra_vde_writel(vde, 0x00000E34, vde->sxe, 0x5C); | |
329 | tegra_vde_writel(vde, 0x063C063C, vde->mce, 0x10); | |
330 | tegra_vde_writel(vde, 0x0003FC00, vde->bsev, INTR_STATUS); | |
331 | tegra_vde_writel(vde, 0x0000150D, vde->bsev, BSE_CONFIG); | |
332 | tegra_vde_writel(vde, 0x00000100, vde->bsev, BSE_INT_ENB); | |
333 | tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x98); | |
334 | tegra_vde_writel(vde, 0x00000060, vde->bsev, 0x9C); | |
cd6c56fe DO |
335 | |
336 | memset(vde->iram + 128, 0, macroblocks_nb / 2); | |
337 | ||
338 | tegra_setup_frameidx(vde, dpb_frames, ctx->dpb_frames_nb, | |
339 | ctx->pic_width_in_mbs, ctx->pic_height_in_mbs); | |
340 | ||
341 | tegra_vde_setup_iram_tables(vde, dpb_frames, | |
342 | ctx->dpb_frames_nb - 1, | |
343 | ctx->dpb_ref_frames_with_earlier_poc_nb); | |
f072c44f DO |
344 | |
345 | /* | |
346 | * The IRAM mapping is write-combine, ensure that CPU buffers have | |
347 | * been flushed at this point. | |
348 | */ | |
cd6c56fe DO |
349 | wmb(); |
350 | ||
91dc5e91 DO |
351 | tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x8C); |
352 | tegra_vde_writel(vde, bitstream_data_addr + bitstream_data_size, | |
353 | vde->bsev, 0x54); | |
cd6c56fe DO |
354 | |
355 | value = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3; | |
356 | ||
91dc5e91 | 357 | tegra_vde_writel(vde, value, vde->bsev, 0x88); |
cd6c56fe DO |
358 | |
359 | err = tegra_vde_wait_bsev(vde, false); | |
360 | if (err) | |
361 | return err; | |
362 | ||
363 | err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x800003FC, false); | |
364 | if (err) | |
365 | return err; | |
366 | ||
367 | value = 0x01500000; | |
368 | value |= ((vde->iram_lists_addr + 512) >> 2) & 0xFFFF; | |
369 | ||
370 | err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); | |
371 | if (err) | |
372 | return err; | |
373 | ||
374 | err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x840F054C, false); | |
375 | if (err) | |
376 | return err; | |
377 | ||
378 | err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x80000080, false); | |
379 | if (err) | |
380 | return err; | |
381 | ||
382 | value = 0x0E340000 | ((vde->iram_lists_addr >> 2) & 0xFFFF); | |
383 | ||
384 | err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); | |
385 | if (err) | |
386 | return err; | |
387 | ||
388 | value = 0x00800005; | |
389 | value |= ctx->pic_width_in_mbs << 11; | |
390 | value |= ctx->pic_height_in_mbs << 3; | |
391 | ||
91dc5e91 | 392 | tegra_vde_writel(vde, value, vde->sxe, 0x10); |
cd6c56fe DO |
393 | |
394 | value = !ctx->baseline_profile << 17; | |
395 | value |= ctx->level_idc << 13; | |
396 | value |= ctx->log2_max_pic_order_cnt_lsb << 7; | |
397 | value |= ctx->pic_order_cnt_type << 5; | |
398 | value |= ctx->log2_max_frame_num; | |
399 | ||
91dc5e91 | 400 | tegra_vde_writel(vde, value, vde->sxe, 0x40); |
cd6c56fe DO |
401 | |
402 | value = ctx->pic_init_qp << 25; | |
403 | value |= !!(ctx->deblocking_filter_control_present_flag) << 2; | |
404 | value |= !!ctx->pic_order_present_flag; | |
405 | ||
91dc5e91 | 406 | tegra_vde_writel(vde, value, vde->sxe, 0x44); |
cd6c56fe DO |
407 | |
408 | value = ctx->chroma_qp_index_offset; | |
409 | value |= ctx->num_ref_idx_l0_active_minus1 << 5; | |
410 | value |= ctx->num_ref_idx_l1_active_minus1 << 10; | |
411 | value |= !!ctx->constrained_intra_pred_flag << 15; | |
412 | ||
91dc5e91 | 413 | tegra_vde_writel(vde, value, vde->sxe, 0x48); |
cd6c56fe DO |
414 | |
415 | value = 0x0C000000; | |
416 | value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 24; | |
417 | ||
91dc5e91 | 418 | tegra_vde_writel(vde, value, vde->sxe, 0x4C); |
cd6c56fe DO |
419 | |
420 | value = 0x03800000; | |
17aed904 | 421 | value |= bitstream_data_size & GENMASK(19, 15); |
cd6c56fe | 422 | |
91dc5e91 | 423 | tegra_vde_writel(vde, value, vde->sxe, 0x68); |
cd6c56fe | 424 | |
91dc5e91 | 425 | tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C); |
cd6c56fe DO |
426 | |
427 | value = 0x10000005; | |
428 | value |= ctx->pic_width_in_mbs << 11; | |
429 | value |= ctx->pic_height_in_mbs << 3; | |
430 | ||
91dc5e91 | 431 | tegra_vde_writel(vde, value, vde->mbe, 0x80); |
cd6c56fe DO |
432 | |
433 | value = 0x26800000; | |
434 | value |= ctx->level_idc << 4; | |
435 | value |= !ctx->baseline_profile << 1; | |
436 | value |= !!ctx->direct_8x8_inference_flag; | |
437 | ||
91dc5e91 | 438 | tegra_vde_writel(vde, value, vde->mbe, 0x80); |
cd6c56fe | 439 | |
91dc5e91 DO |
440 | tegra_vde_writel(vde, 0xF4000001, vde->mbe, 0x80); |
441 | tegra_vde_writel(vde, 0x20000000, vde->mbe, 0x80); | |
442 | tegra_vde_writel(vde, 0xF4000101, vde->mbe, 0x80); | |
cd6c56fe DO |
443 | |
444 | value = 0x20000000; | |
445 | value |= ctx->chroma_qp_index_offset << 8; | |
446 | ||
91dc5e91 | 447 | tegra_vde_writel(vde, value, vde->mbe, 0x80); |
cd6c56fe DO |
448 | |
449 | err = tegra_vde_setup_mbe_frame_idx(vde, | |
450 | ctx->dpb_frames_nb - 1, | |
451 | ctx->pic_order_cnt_type == 0); | |
452 | if (err) { | |
453 | dev_err(dev, "MBE frames setup failed %d\n", err); | |
454 | return err; | |
455 | } | |
456 | ||
457 | tegra_vde_mbe_set_0xa_reg(vde, 0, 0x000009FC); | |
458 | tegra_vde_mbe_set_0xa_reg(vde, 2, 0x61DEAD00); | |
459 | tegra_vde_mbe_set_0xa_reg(vde, 4, 0x62DEAD00); | |
460 | tegra_vde_mbe_set_0xa_reg(vde, 6, 0x63DEAD00); | |
461 | tegra_vde_mbe_set_0xa_reg(vde, 8, dpb_frames[0].aux_addr); | |
462 | ||
463 | value = 0xFC000000; | |
464 | value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 2; | |
465 | ||
466 | if (!ctx->baseline_profile) | |
467 | value |= !!(dpb_frames[0].flags & FLAG_REFERENCE) << 1; | |
468 | ||
91dc5e91 | 469 | tegra_vde_writel(vde, value, vde->mbe, 0x80); |
cd6c56fe DO |
470 | |
471 | err = tegra_vde_wait_mbe(vde); | |
472 | if (err) { | |
473 | dev_err(dev, "MBE programming failed %d\n", err); | |
474 | return err; | |
475 | } | |
476 | ||
477 | return 0; | |
478 | } | |
479 | ||
480 | static void tegra_vde_decode_frame(struct tegra_vde *vde, | |
481 | unsigned int macroblocks_nb) | |
482 | { | |
483 | reinit_completion(&vde->decode_completion); | |
484 | ||
91dc5e91 DO |
485 | tegra_vde_writel(vde, 0x00000001, vde->bsev, 0x8C); |
486 | tegra_vde_writel(vde, 0x20000000 | (macroblocks_nb - 1), | |
487 | vde->sxe, 0x00); | |
cd6c56fe DO |
488 | } |
489 | ||
b301f8de | 490 | static int tegra_vde_attach_dmabuf(struct tegra_vde *vde, |
cd6c56fe DO |
491 | int fd, |
492 | unsigned long offset, | |
17aed904 DO |
493 | size_t min_size, |
494 | size_t align_size, | |
cd6c56fe | 495 | struct dma_buf_attachment **a, |
b301f8de | 496 | dma_addr_t *addrp, |
cd6c56fe DO |
497 | size_t *size, |
498 | enum dma_data_direction dma_dir) | |
499 | { | |
b301f8de | 500 | struct device *dev = vde->miscdev.parent; |
cd6c56fe | 501 | struct dma_buf *dmabuf; |
cd6c56fe DO |
502 | int err; |
503 | ||
504 | dmabuf = dma_buf_get(fd); | |
505 | if (IS_ERR(dmabuf)) { | |
506 | dev_err(dev, "Invalid dmabuf FD\n"); | |
507 | return PTR_ERR(dmabuf); | |
508 | } | |
509 | ||
17aed904 | 510 | if (dmabuf->size & (align_size - 1)) { |
f072c44f | 511 | dev_err(dev, "Unaligned dmabuf 0x%zX, should be aligned to 0x%zX\n", |
17aed904 DO |
512 | dmabuf->size, align_size); |
513 | return -EINVAL; | |
514 | } | |
515 | ||
cd6c56fe | 516 | if ((u64)offset + min_size > dmabuf->size) { |
f072c44f | 517 | dev_err(dev, "Too small dmabuf size %zu @0x%lX, should be at least %zu\n", |
cd6c56fe DO |
518 | dmabuf->size, offset, min_size); |
519 | return -EINVAL; | |
520 | } | |
521 | ||
92cd1440 DO |
522 | err = tegra_vde_dmabuf_cache_map(vde, dmabuf, dma_dir, a, addrp); |
523 | if (err) | |
cd6c56fe | 524 | goto err_put; |
b301f8de DO |
525 | |
526 | *addrp = *addrp + offset; | |
cd6c56fe DO |
527 | |
528 | if (size) | |
529 | *size = dmabuf->size - offset; | |
530 | ||
531 | return 0; | |
532 | ||
cd6c56fe DO |
533 | err_put: |
534 | dma_buf_put(dmabuf); | |
535 | ||
536 | return err; | |
537 | } | |
538 | ||
b301f8de | 539 | static int tegra_vde_attach_dmabufs_to_frame(struct tegra_vde *vde, |
cd6c56fe DO |
540 | struct video_frame *frame, |
541 | struct tegra_vde_h264_frame *src, | |
542 | enum dma_data_direction dma_dir, | |
543 | bool baseline_profile, | |
3830e4f2 | 544 | size_t lsize, size_t csize) |
cd6c56fe DO |
545 | { |
546 | int err; | |
547 | ||
b301f8de | 548 | err = tegra_vde_attach_dmabuf(vde, src->y_fd, |
3830e4f2 | 549 | src->y_offset, lsize, SZ_256, |
cd6c56fe DO |
550 | &frame->y_dmabuf_attachment, |
551 | &frame->y_addr, | |
cd6c56fe DO |
552 | NULL, dma_dir); |
553 | if (err) | |
554 | return err; | |
555 | ||
b301f8de | 556 | err = tegra_vde_attach_dmabuf(vde, src->cb_fd, |
17aed904 | 557 | src->cb_offset, csize, SZ_256, |
cd6c56fe DO |
558 | &frame->cb_dmabuf_attachment, |
559 | &frame->cb_addr, | |
cd6c56fe DO |
560 | NULL, dma_dir); |
561 | if (err) | |
562 | goto err_release_y; | |
563 | ||
b301f8de | 564 | err = tegra_vde_attach_dmabuf(vde, src->cr_fd, |
17aed904 | 565 | src->cr_offset, csize, SZ_256, |
cd6c56fe DO |
566 | &frame->cr_dmabuf_attachment, |
567 | &frame->cr_addr, | |
cd6c56fe DO |
568 | NULL, dma_dir); |
569 | if (err) | |
570 | goto err_release_cb; | |
571 | ||
572 | if (baseline_profile) { | |
573 | frame->aux_addr = 0x64DEAD00; | |
574 | return 0; | |
575 | } | |
576 | ||
b301f8de | 577 | err = tegra_vde_attach_dmabuf(vde, src->aux_fd, |
17aed904 | 578 | src->aux_offset, csize, SZ_256, |
cd6c56fe DO |
579 | &frame->aux_dmabuf_attachment, |
580 | &frame->aux_addr, | |
cd6c56fe DO |
581 | NULL, dma_dir); |
582 | if (err) | |
583 | goto err_release_cr; | |
584 | ||
585 | return 0; | |
586 | ||
587 | err_release_cr: | |
92cd1440 | 588 | tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, true); |
cd6c56fe | 589 | err_release_cb: |
92cd1440 | 590 | tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, true); |
cd6c56fe | 591 | err_release_y: |
92cd1440 | 592 | tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, true); |
cd6c56fe DO |
593 | |
594 | return err; | |
595 | } | |
596 | ||
b301f8de DO |
597 | static void tegra_vde_release_frame_dmabufs(struct tegra_vde *vde, |
598 | struct video_frame *frame, | |
cd6c56fe | 599 | enum dma_data_direction dma_dir, |
92cd1440 DO |
600 | bool baseline_profile, |
601 | bool release) | |
cd6c56fe DO |
602 | { |
603 | if (!baseline_profile) | |
92cd1440 DO |
604 | tegra_vde_dmabuf_cache_unmap(vde, frame->aux_dmabuf_attachment, |
605 | release); | |
606 | ||
607 | tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, release); | |
608 | tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, release); | |
609 | tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, release); | |
cd6c56fe DO |
610 | } |
611 | ||
612 | static int tegra_vde_validate_frame(struct device *dev, | |
613 | struct tegra_vde_h264_frame *frame) | |
614 | { | |
615 | if (frame->frame_num > 0x7FFFFF) { | |
616 | dev_err(dev, "Bad frame_num %u\n", frame->frame_num); | |
617 | return -EINVAL; | |
618 | } | |
619 | ||
cd6c56fe DO |
620 | return 0; |
621 | } | |
622 | ||
623 | static int tegra_vde_validate_h264_ctx(struct device *dev, | |
624 | struct tegra_vde_h264_decoder_ctx *ctx) | |
625 | { | |
626 | if (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) { | |
627 | dev_err(dev, "Bad DPB size %u\n", ctx->dpb_frames_nb); | |
628 | return -EINVAL; | |
629 | } | |
630 | ||
631 | if (ctx->level_idc > 15) { | |
632 | dev_err(dev, "Bad level value %u\n", ctx->level_idc); | |
633 | return -EINVAL; | |
634 | } | |
635 | ||
636 | if (ctx->pic_init_qp > 52) { | |
637 | dev_err(dev, "Bad pic_init_qp value %u\n", ctx->pic_init_qp); | |
638 | return -EINVAL; | |
639 | } | |
640 | ||
641 | if (ctx->log2_max_pic_order_cnt_lsb > 16) { | |
642 | dev_err(dev, "Bad log2_max_pic_order_cnt_lsb value %u\n", | |
643 | ctx->log2_max_pic_order_cnt_lsb); | |
644 | return -EINVAL; | |
645 | } | |
646 | ||
647 | if (ctx->log2_max_frame_num > 16) { | |
648 | dev_err(dev, "Bad log2_max_frame_num value %u\n", | |
649 | ctx->log2_max_frame_num); | |
650 | return -EINVAL; | |
651 | } | |
652 | ||
653 | if (ctx->chroma_qp_index_offset > 31) { | |
654 | dev_err(dev, "Bad chroma_qp_index_offset value %u\n", | |
655 | ctx->chroma_qp_index_offset); | |
656 | return -EINVAL; | |
657 | } | |
658 | ||
659 | if (ctx->pic_order_cnt_type > 2) { | |
660 | dev_err(dev, "Bad pic_order_cnt_type value %u\n", | |
661 | ctx->pic_order_cnt_type); | |
662 | return -EINVAL; | |
663 | } | |
664 | ||
665 | if (ctx->num_ref_idx_l0_active_minus1 > 15) { | |
666 | dev_err(dev, "Bad num_ref_idx_l0_active_minus1 value %u\n", | |
667 | ctx->num_ref_idx_l0_active_minus1); | |
668 | return -EINVAL; | |
669 | } | |
670 | ||
671 | if (ctx->num_ref_idx_l1_active_minus1 > 15) { | |
672 | dev_err(dev, "Bad num_ref_idx_l1_active_minus1 value %u\n", | |
673 | ctx->num_ref_idx_l1_active_minus1); | |
674 | return -EINVAL; | |
675 | } | |
676 | ||
677 | if (!ctx->pic_width_in_mbs || ctx->pic_width_in_mbs > 127) { | |
678 | dev_err(dev, "Bad pic_width_in_mbs value %u\n", | |
679 | ctx->pic_width_in_mbs); | |
680 | return -EINVAL; | |
681 | } | |
682 | ||
683 | if (!ctx->pic_height_in_mbs || ctx->pic_height_in_mbs > 127) { | |
684 | dev_err(dev, "Bad pic_height_in_mbs value %u\n", | |
685 | ctx->pic_height_in_mbs); | |
686 | return -EINVAL; | |
687 | } | |
688 | ||
689 | return 0; | |
690 | } | |
691 | ||
692 | static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, | |
693 | unsigned long vaddr) | |
694 | { | |
695 | struct device *dev = vde->miscdev.parent; | |
696 | struct tegra_vde_h264_decoder_ctx ctx; | |
b1b9b7be | 697 | struct tegra_vde_h264_frame *frames; |
cd6c56fe DO |
698 | struct tegra_vde_h264_frame __user *frames_user; |
699 | struct video_frame *dpb_frames; | |
700 | struct dma_buf_attachment *bitstream_data_dmabuf_attachment; | |
cd6c56fe DO |
701 | enum dma_data_direction dma_dir; |
702 | dma_addr_t bitstream_data_addr; | |
703 | dma_addr_t bsev_ptr; | |
3830e4f2 | 704 | size_t lsize, csize; |
cd6c56fe DO |
705 | size_t bitstream_data_size; |
706 | unsigned int macroblocks_nb; | |
707 | unsigned int read_bytes; | |
3830e4f2 | 708 | unsigned int cstride; |
cd6c56fe DO |
709 | unsigned int i; |
710 | long timeout; | |
711 | int ret, err; | |
712 | ||
713 | if (copy_from_user(&ctx, (void __user *)vaddr, sizeof(ctx))) | |
714 | return -EFAULT; | |
715 | ||
716 | ret = tegra_vde_validate_h264_ctx(dev, &ctx); | |
717 | if (ret) | |
718 | return ret; | |
719 | ||
b301f8de | 720 | ret = tegra_vde_attach_dmabuf(vde, ctx.bitstream_data_fd, |
17aed904 DO |
721 | ctx.bitstream_data_offset, |
722 | SZ_16K, SZ_16K, | |
cd6c56fe DO |
723 | &bitstream_data_dmabuf_attachment, |
724 | &bitstream_data_addr, | |
cd6c56fe DO |
725 | &bitstream_data_size, |
726 | DMA_TO_DEVICE); | |
727 | if (ret) | |
728 | return ret; | |
729 | ||
b1b9b7be DO |
730 | frames = kmalloc_array(ctx.dpb_frames_nb, sizeof(*frames), GFP_KERNEL); |
731 | if (!frames) { | |
732 | ret = -ENOMEM; | |
733 | goto release_bitstream_dmabuf; | |
734 | } | |
735 | ||
cd6c56fe DO |
736 | dpb_frames = kcalloc(ctx.dpb_frames_nb, sizeof(*dpb_frames), |
737 | GFP_KERNEL); | |
738 | if (!dpb_frames) { | |
739 | ret = -ENOMEM; | |
b1b9b7be | 740 | goto free_frames; |
cd6c56fe DO |
741 | } |
742 | ||
743 | macroblocks_nb = ctx.pic_width_in_mbs * ctx.pic_height_in_mbs; | |
744 | frames_user = u64_to_user_ptr(ctx.dpb_frames_ptr); | |
745 | ||
746 | if (copy_from_user(frames, frames_user, | |
747 | ctx.dpb_frames_nb * sizeof(*frames))) { | |
748 | ret = -EFAULT; | |
749 | goto free_dpb_frames; | |
750 | } | |
751 | ||
3830e4f2 DO |
752 | cstride = ALIGN(ctx.pic_width_in_mbs * 8, 16); |
753 | csize = cstride * ctx.pic_height_in_mbs * 8; | |
754 | lsize = macroblocks_nb * 256; | |
755 | ||
cd6c56fe DO |
756 | for (i = 0; i < ctx.dpb_frames_nb; i++) { |
757 | ret = tegra_vde_validate_frame(dev, &frames[i]); | |
758 | if (ret) | |
759 | goto release_dpb_frames; | |
760 | ||
761 | dpb_frames[i].flags = frames[i].flags; | |
762 | dpb_frames[i].frame_num = frames[i].frame_num; | |
763 | ||
764 | dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | |
765 | ||
b301f8de | 766 | ret = tegra_vde_attach_dmabufs_to_frame(vde, &dpb_frames[i], |
cd6c56fe DO |
767 | &frames[i], dma_dir, |
768 | ctx.baseline_profile, | |
3830e4f2 | 769 | lsize, csize); |
cd6c56fe DO |
770 | if (ret) |
771 | goto release_dpb_frames; | |
772 | } | |
773 | ||
774 | ret = mutex_lock_interruptible(&vde->lock); | |
775 | if (ret) | |
776 | goto release_dpb_frames; | |
777 | ||
778 | ret = pm_runtime_get_sync(dev); | |
779 | if (ret < 0) | |
780 | goto unlock; | |
781 | ||
782 | /* | |
783 | * We rely on the VDE registers reset value, otherwise VDE | |
784 | * causes bus lockup. | |
785 | */ | |
f68bbb23 DO |
786 | ret = reset_control_assert(vde->rst_mc); |
787 | if (ret) { | |
788 | dev_err(dev, "DEC start: Failed to assert MC reset: %d\n", | |
789 | ret); | |
790 | goto put_runtime_pm; | |
791 | } | |
792 | ||
cd6c56fe DO |
793 | ret = reset_control_reset(vde->rst); |
794 | if (ret) { | |
f68bbb23 DO |
795 | dev_err(dev, "DEC start: Failed to reset HW: %d\n", ret); |
796 | goto put_runtime_pm; | |
797 | } | |
798 | ||
799 | ret = reset_control_deassert(vde->rst_mc); | |
800 | if (ret) { | |
801 | dev_err(dev, "DEC start: Failed to deassert MC reset: %d\n", | |
802 | ret); | |
cd6c56fe DO |
803 | goto put_runtime_pm; |
804 | } | |
805 | ||
806 | ret = tegra_vde_setup_hw_context(vde, &ctx, dpb_frames, | |
807 | bitstream_data_addr, | |
808 | bitstream_data_size, | |
809 | macroblocks_nb); | |
810 | if (ret) | |
811 | goto put_runtime_pm; | |
812 | ||
813 | tegra_vde_decode_frame(vde, macroblocks_nb); | |
814 | ||
815 | timeout = wait_for_completion_interruptible_timeout( | |
816 | &vde->decode_completion, msecs_to_jiffies(1000)); | |
817 | if (timeout == 0) { | |
91dc5e91 DO |
818 | bsev_ptr = tegra_vde_readl(vde, vde->bsev, 0x10); |
819 | macroblocks_nb = tegra_vde_readl(vde, vde->sxe, 0xC8) & 0x1FFF; | |
cd6c56fe DO |
820 | read_bytes = bsev_ptr ? bsev_ptr - bitstream_data_addr : 0; |
821 | ||
f072c44f | 822 | dev_err(dev, "Decoding failed: read 0x%X bytes, %u macroblocks parsed\n", |
cd6c56fe DO |
823 | read_bytes, macroblocks_nb); |
824 | ||
825 | ret = -EIO; | |
826 | } else if (timeout < 0) { | |
827 | ret = timeout; | |
828 | } | |
829 | ||
f68bbb23 DO |
830 | /* |
831 | * At first reset memory client to avoid resetting VDE HW in the | |
832 | * middle of DMA which could result into memory corruption or hang | |
833 | * the whole system. | |
834 | */ | |
835 | err = reset_control_assert(vde->rst_mc); | |
f956aec0 | 836 | if (err) |
f68bbb23 | 837 | dev_err(dev, "DEC end: Failed to assert MC reset: %d\n", err); |
f956aec0 DO |
838 | |
839 | err = reset_control_assert(vde->rst); | |
840 | if (err) | |
841 | dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); | |
cd6c56fe DO |
842 | |
843 | put_runtime_pm: | |
844 | pm_runtime_mark_last_busy(dev); | |
845 | pm_runtime_put_autosuspend(dev); | |
846 | ||
847 | unlock: | |
848 | mutex_unlock(&vde->lock); | |
849 | ||
850 | release_dpb_frames: | |
851 | while (i--) { | |
852 | dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | |
853 | ||
b301f8de | 854 | tegra_vde_release_frame_dmabufs(vde, &dpb_frames[i], dma_dir, |
92cd1440 | 855 | ctx.baseline_profile, ret != 0); |
cd6c56fe DO |
856 | } |
857 | ||
858 | free_dpb_frames: | |
859 | kfree(dpb_frames); | |
860 | ||
b1b9b7be DO |
861 | free_frames: |
862 | kfree(frames); | |
863 | ||
cd6c56fe | 864 | release_bitstream_dmabuf: |
92cd1440 DO |
865 | tegra_vde_dmabuf_cache_unmap(vde, bitstream_data_dmabuf_attachment, |
866 | ret != 0); | |
cd6c56fe DO |
867 | |
868 | return ret; | |
869 | } | |
870 | ||
871 | static long tegra_vde_unlocked_ioctl(struct file *filp, | |
872 | unsigned int cmd, unsigned long arg) | |
873 | { | |
874 | struct miscdevice *miscdev = filp->private_data; | |
875 | struct tegra_vde *vde = container_of(miscdev, struct tegra_vde, | |
876 | miscdev); | |
877 | ||
878 | switch (cmd) { | |
879 | case TEGRA_VDE_IOCTL_DECODE_H264: | |
880 | return tegra_vde_ioctl_decode_h264(vde, arg); | |
881 | } | |
882 | ||
883 | dev_err(miscdev->parent, "Invalid IOCTL command %u\n", cmd); | |
884 | ||
885 | return -ENOTTY; | |
886 | } | |
887 | ||
92cd1440 DO |
888 | static int tegra_vde_release_file(struct inode *inode, struct file *filp) |
889 | { | |
890 | struct miscdevice *miscdev = filp->private_data; | |
891 | struct tegra_vde *vde = container_of(miscdev, struct tegra_vde, | |
892 | miscdev); | |
893 | ||
894 | tegra_vde_dmabuf_cache_unmap_sync(vde); | |
895 | ||
896 | return 0; | |
897 | } | |
898 | ||
cd6c56fe DO |
899 | static const struct file_operations tegra_vde_fops = { |
900 | .owner = THIS_MODULE, | |
901 | .unlocked_ioctl = tegra_vde_unlocked_ioctl, | |
92cd1440 | 902 | .release = tegra_vde_release_file, |
cd6c56fe DO |
903 | }; |
904 | ||
905 | static irqreturn_t tegra_vde_isr(int irq, void *data) | |
906 | { | |
907 | struct tegra_vde *vde = data; | |
908 | ||
2efa20da DO |
909 | if (completion_done(&vde->decode_completion)) |
910 | return IRQ_NONE; | |
911 | ||
91dc5e91 | 912 | tegra_vde_set_bits(vde, 0, vde->frameid, 0x208); |
cd6c56fe DO |
913 | complete(&vde->decode_completion); |
914 | ||
915 | return IRQ_HANDLED; | |
916 | } | |
917 | ||
918 | static int tegra_vde_runtime_suspend(struct device *dev) | |
919 | { | |
920 | struct tegra_vde *vde = dev_get_drvdata(dev); | |
921 | int err; | |
922 | ||
923 | err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC); | |
924 | if (err) { | |
925 | dev_err(dev, "Failed to power down HW: %d\n", err); | |
926 | return err; | |
927 | } | |
928 | ||
929 | clk_disable_unprepare(vde->clk); | |
930 | ||
931 | return 0; | |
932 | } | |
933 | ||
934 | static int tegra_vde_runtime_resume(struct device *dev) | |
935 | { | |
936 | struct tegra_vde *vde = dev_get_drvdata(dev); | |
937 | int err; | |
938 | ||
939 | err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC, | |
940 | vde->clk, vde->rst); | |
941 | if (err) { | |
942 | dev_err(dev, "Failed to power up HW : %d\n", err); | |
943 | return err; | |
944 | } | |
945 | ||
946 | return 0; | |
947 | } | |
948 | ||
949 | static int tegra_vde_probe(struct platform_device *pdev) | |
950 | { | |
951 | struct device *dev = &pdev->dev; | |
cd6c56fe DO |
952 | struct tegra_vde *vde; |
953 | int irq, err; | |
954 | ||
955 | vde = devm_kzalloc(dev, sizeof(*vde), GFP_KERNEL); | |
956 | if (!vde) | |
957 | return -ENOMEM; | |
958 | ||
959 | platform_set_drvdata(pdev, vde); | |
960 | ||
7af80a69 | 961 | vde->sxe = devm_platform_ioremap_resource_byname(pdev, "sxe"); |
cd6c56fe DO |
962 | if (IS_ERR(vde->sxe)) |
963 | return PTR_ERR(vde->sxe); | |
964 | ||
7af80a69 | 965 | vde->bsev = devm_platform_ioremap_resource_byname(pdev, "bsev"); |
cd6c56fe DO |
966 | if (IS_ERR(vde->bsev)) |
967 | return PTR_ERR(vde->bsev); | |
968 | ||
7af80a69 | 969 | vde->mbe = devm_platform_ioremap_resource_byname(pdev, "mbe"); |
cd6c56fe DO |
970 | if (IS_ERR(vde->mbe)) |
971 | return PTR_ERR(vde->mbe); | |
972 | ||
7af80a69 | 973 | vde->ppe = devm_platform_ioremap_resource_byname(pdev, "ppe"); |
cd6c56fe DO |
974 | if (IS_ERR(vde->ppe)) |
975 | return PTR_ERR(vde->ppe); | |
976 | ||
7af80a69 | 977 | vde->mce = devm_platform_ioremap_resource_byname(pdev, "mce"); |
cd6c56fe DO |
978 | if (IS_ERR(vde->mce)) |
979 | return PTR_ERR(vde->mce); | |
980 | ||
7af80a69 | 981 | vde->tfe = devm_platform_ioremap_resource_byname(pdev, "tfe"); |
cd6c56fe DO |
982 | if (IS_ERR(vde->tfe)) |
983 | return PTR_ERR(vde->tfe); | |
984 | ||
7af80a69 | 985 | vde->ppb = devm_platform_ioremap_resource_byname(pdev, "ppb"); |
cd6c56fe DO |
986 | if (IS_ERR(vde->ppb)) |
987 | return PTR_ERR(vde->ppb); | |
988 | ||
7af80a69 | 989 | vde->vdma = devm_platform_ioremap_resource_byname(pdev, "vdma"); |
cd6c56fe DO |
990 | if (IS_ERR(vde->vdma)) |
991 | return PTR_ERR(vde->vdma); | |
992 | ||
7af80a69 | 993 | vde->frameid = devm_platform_ioremap_resource_byname(pdev, "frameid"); |
cd6c56fe DO |
994 | if (IS_ERR(vde->frameid)) |
995 | return PTR_ERR(vde->frameid); | |
996 | ||
997 | vde->clk = devm_clk_get(dev, NULL); | |
998 | if (IS_ERR(vde->clk)) { | |
999 | err = PTR_ERR(vde->clk); | |
1000 | dev_err(dev, "Could not get VDE clk %d\n", err); | |
1001 | return err; | |
1002 | } | |
1003 | ||
1004 | vde->rst = devm_reset_control_get(dev, NULL); | |
1005 | if (IS_ERR(vde->rst)) { | |
1006 | err = PTR_ERR(vde->rst); | |
1007 | dev_err(dev, "Could not get VDE reset %d\n", err); | |
1008 | return err; | |
1009 | } | |
1010 | ||
f68bbb23 DO |
1011 | vde->rst_mc = devm_reset_control_get_optional(dev, "mc"); |
1012 | if (IS_ERR(vde->rst_mc)) { | |
1013 | err = PTR_ERR(vde->rst_mc); | |
1014 | dev_err(dev, "Could not get MC reset %d\n", err); | |
1015 | return err; | |
1016 | } | |
1017 | ||
cd6c56fe DO |
1018 | irq = platform_get_irq_byname(pdev, "sync-token"); |
1019 | if (irq < 0) | |
1020 | return irq; | |
1021 | ||
1022 | err = devm_request_irq(dev, irq, tegra_vde_isr, 0, | |
1023 | dev_name(dev), vde); | |
1024 | if (err) { | |
1025 | dev_err(dev, "Could not request IRQ %d\n", err); | |
1026 | return err; | |
1027 | } | |
1028 | ||
1029 | vde->iram_pool = of_gen_pool_get(dev->of_node, "iram", 0); | |
1030 | if (!vde->iram_pool) { | |
1031 | dev_err(dev, "Could not get IRAM pool\n"); | |
1032 | return -EPROBE_DEFER; | |
1033 | } | |
1034 | ||
1035 | vde->iram = gen_pool_dma_alloc(vde->iram_pool, | |
1036 | gen_pool_size(vde->iram_pool), | |
1037 | &vde->iram_lists_addr); | |
1038 | if (!vde->iram) { | |
1039 | dev_err(dev, "Could not reserve IRAM\n"); | |
1040 | return -ENOMEM; | |
1041 | } | |
1042 | ||
92cd1440 DO |
1043 | INIT_LIST_HEAD(&vde->map_list); |
1044 | mutex_init(&vde->map_lock); | |
cd6c56fe DO |
1045 | mutex_init(&vde->lock); |
1046 | init_completion(&vde->decode_completion); | |
1047 | ||
1048 | vde->miscdev.minor = MISC_DYNAMIC_MINOR; | |
1049 | vde->miscdev.name = "tegra_vde"; | |
1050 | vde->miscdev.fops = &tegra_vde_fops; | |
1051 | vde->miscdev.parent = dev; | |
1052 | ||
b301f8de DO |
1053 | err = tegra_vde_iommu_init(vde); |
1054 | if (err) { | |
1055 | dev_err(dev, "Failed to initialize IOMMU: %d\n", err); | |
1056 | goto err_gen_free; | |
1057 | } | |
1058 | ||
cd6c56fe DO |
1059 | err = misc_register(&vde->miscdev); |
1060 | if (err) { | |
1061 | dev_err(dev, "Failed to register misc device: %d\n", err); | |
b301f8de | 1062 | goto err_deinit_iommu; |
cd6c56fe DO |
1063 | } |
1064 | ||
1065 | pm_runtime_enable(dev); | |
1066 | pm_runtime_use_autosuspend(dev); | |
1067 | pm_runtime_set_autosuspend_delay(dev, 300); | |
1068 | ||
1069 | if (!pm_runtime_enabled(dev)) { | |
1070 | err = tegra_vde_runtime_resume(dev); | |
1071 | if (err) | |
1072 | goto err_misc_unreg; | |
1073 | } | |
1074 | ||
1075 | return 0; | |
1076 | ||
1077 | err_misc_unreg: | |
1078 | misc_deregister(&vde->miscdev); | |
1079 | ||
b301f8de DO |
1080 | err_deinit_iommu: |
1081 | tegra_vde_iommu_deinit(vde); | |
1082 | ||
cd6c56fe DO |
1083 | err_gen_free: |
1084 | gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, | |
1085 | gen_pool_size(vde->iram_pool)); | |
1086 | ||
1087 | return err; | |
1088 | } | |
1089 | ||
1090 | static int tegra_vde_remove(struct platform_device *pdev) | |
1091 | { | |
1092 | struct tegra_vde *vde = platform_get_drvdata(pdev); | |
1093 | struct device *dev = &pdev->dev; | |
1094 | int err; | |
1095 | ||
1096 | if (!pm_runtime_enabled(dev)) { | |
1097 | err = tegra_vde_runtime_suspend(dev); | |
1098 | if (err) | |
1099 | return err; | |
1100 | } | |
1101 | ||
1102 | pm_runtime_dont_use_autosuspend(dev); | |
1103 | pm_runtime_disable(dev); | |
1104 | ||
1105 | misc_deregister(&vde->miscdev); | |
1106 | ||
92cd1440 | 1107 | tegra_vde_dmabuf_cache_unmap_all(vde); |
b301f8de DO |
1108 | tegra_vde_iommu_deinit(vde); |
1109 | ||
cd6c56fe DO |
1110 | gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, |
1111 | gen_pool_size(vde->iram_pool)); | |
1112 | ||
1113 | return 0; | |
1114 | } | |
1115 | ||
3a909680 | 1116 | static __maybe_unused int tegra_vde_pm_suspend(struct device *dev) |
cd6c56fe DO |
1117 | { |
1118 | struct tegra_vde *vde = dev_get_drvdata(dev); | |
1119 | int err; | |
1120 | ||
1121 | mutex_lock(&vde->lock); | |
1122 | ||
1123 | err = pm_runtime_force_suspend(dev); | |
1124 | if (err < 0) | |
1125 | return err; | |
1126 | ||
1127 | return 0; | |
1128 | } | |
1129 | ||
3a909680 | 1130 | static __maybe_unused int tegra_vde_pm_resume(struct device *dev) |
cd6c56fe DO |
1131 | { |
1132 | struct tegra_vde *vde = dev_get_drvdata(dev); | |
1133 | int err; | |
1134 | ||
1135 | err = pm_runtime_force_resume(dev); | |
1136 | if (err < 0) | |
1137 | return err; | |
1138 | ||
1139 | mutex_unlock(&vde->lock); | |
1140 | ||
1141 | return 0; | |
1142 | } | |
cd6c56fe DO |
1143 | |
1144 | static const struct dev_pm_ops tegra_vde_pm_ops = { | |
1145 | SET_RUNTIME_PM_OPS(tegra_vde_runtime_suspend, | |
1146 | tegra_vde_runtime_resume, | |
1147 | NULL) | |
1148 | SET_SYSTEM_SLEEP_PM_OPS(tegra_vde_pm_suspend, | |
1149 | tegra_vde_pm_resume) | |
1150 | }; | |
1151 | ||
1152 | static const struct of_device_id tegra_vde_of_match[] = { | |
1153 | { .compatible = "nvidia,tegra20-vde", }, | |
1154 | { }, | |
1155 | }; | |
1156 | MODULE_DEVICE_TABLE(of, tegra_vde_of_match); | |
1157 | ||
1158 | static struct platform_driver tegra_vde_driver = { | |
1159 | .probe = tegra_vde_probe, | |
1160 | .remove = tegra_vde_remove, | |
1161 | .driver = { | |
1162 | .name = "tegra-vde", | |
1163 | .of_match_table = tegra_vde_of_match, | |
1164 | .pm = &tegra_vde_pm_ops, | |
1165 | }, | |
1166 | }; | |
1167 | module_platform_driver(tegra_vde_driver); | |
1168 | ||
1169 | MODULE_DESCRIPTION("NVIDIA Tegra Video Decoder driver"); | |
1170 | MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); | |
1171 | MODULE_LICENSE("GPL"); |