This source file includes following definitions.
- get_hw_reg_base
- write_hw_segmentation_data
- read_hw_segmentation_data
- enable_hw_rw_function
- store_dec_table
- load_dec_table
- get_pic_info
- vp8_dec_finish
- move_fb_list_use_to_free
- init_list
- add_fb_to_free_list
- alloc_working_buf
- free_working_buf
- vdec_vp8_init
- vdec_vp8_decode
- get_disp_fb
- get_free_fb
- get_crop_info
- vdec_vp8_get_param
- vdec_vp8_deinit
1
2
3
4
5
6
7
8 #include <linux/slab.h>
9 #include "../vdec_drv_if.h"
10 #include "../mtk_vcodec_util.h"
11 #include "../mtk_vcodec_dec.h"
12 #include "../mtk_vcodec_intr.h"
13 #include "../vdec_vpu_if.h"
14 #include "../vdec_drv_base.h"
15
16
17 #define VP8_DPB_SIZE 4
18
19
20 #define VP8_WORKING_BUF_SZ (45 * 4096)
21
22
23 #define VP8_SEGID_DRAM_ADDR 0x3c
24 #define VP8_HW_VLD_ADDR 0x93C
25 #define VP8_HW_VLD_VALUE 0x940
26 #define VP8_BSASET 0x100
27 #define VP8_BSDSET 0x104
28 #define VP8_RW_CKEN_SET 0x0
29 #define VP8_RW_DCM_CON 0x18
30 #define VP8_WO_VLD_SRST 0x108
31 #define VP8_RW_MISC_SYS_SEL 0x84
32 #define VP8_RW_MISC_SPEC_CON 0xC8
33 #define VP8_WO_VLD_SRST 0x108
34 #define VP8_RW_VP8_CTRL 0xA4
35 #define VP8_RW_MISC_DCM_CON 0xEC
36 #define VP8_RW_MISC_SRST 0xF4
37 #define VP8_RW_MISC_FUNC_CON 0xCC
38
39 #define VP8_MAX_FRM_BUF_NUM 5
40 #define VP8_MAX_FRM_BUF_NODE_NUM (VP8_MAX_FRM_BUF_NUM * 2)
41
42
43 #define VP8_HW_SEGMENT_DATA_SZ 272
44 #define VP8_HW_SEGMENT_UINT 4
45
46 #define VP8_DEC_TABLE_PROC_LOOP 96
47 #define VP8_DEC_TABLE_UNIT 3
48 #define VP8_DEC_TABLE_SZ 300
49 #define VP8_DEC_TABLE_OFFSET 2
50 #define VP8_DEC_TABLE_RW_UNIT 4
51
52
53
54
55
56
57
58
59
60
61
62
63
64 struct vdec_vp8_dec_info {
65 uint64_t working_buf_dma;
66 uint64_t prev_y_dma;
67 uint64_t cur_y_fb_dma;
68 uint64_t cur_c_fb_dma;
69 uint64_t bs_dma;
70 uint32_t bs_sz;
71 uint32_t resolution_changed;
72 uint32_t show_frame;
73 uint32_t wait_key_frame;
74 };
75
76
77
78
79
80
81
82
83
84 struct vdec_vp8_vsi {
85 struct vdec_vp8_dec_info dec;
86 struct vdec_pic_info pic;
87 uint32_t dec_table[VP8_DEC_TABLE_SZ];
88 uint32_t segment_buf[VP8_HW_SEGMENT_DATA_SZ][VP8_HW_SEGMENT_UINT];
89 uint32_t load_data;
90 };
91
92
93
94
95
96
97
98
99
100
101
102 struct vdec_vp8_hw_reg_base {
103 void __iomem *sys;
104 void __iomem *misc;
105 void __iomem *ld;
106 void __iomem *top;
107 void __iomem *cm;
108 void __iomem *hwd;
109 void __iomem *hwb;
110 };
111
112
113
114
115
116
117
118
119 struct vdec_vp8_vpu_inst {
120 wait_queue_head_t wq_hd;
121 int signaled;
122 int failure;
123 uint32_t inst_addr;
124 };
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 struct vdec_vp8_inst {
154 struct vdec_fb *cur_fb;
155 struct vdec_fb_node dec_fb[VP8_MAX_FRM_BUF_NODE_NUM];
156 struct list_head available_fb_node_list;
157 struct list_head fb_use_list;
158 struct list_head fb_free_list;
159 struct list_head fb_disp_list;
160 struct mtk_vcodec_mem working_buf;
161 struct vdec_vp8_hw_reg_base reg_base;
162 unsigned int frm_cnt;
163 struct mtk_vcodec_ctx *ctx;
164 struct vdec_vpu_inst vpu;
165 struct vdec_vp8_vsi *vsi;
166 };
167
168 static void get_hw_reg_base(struct vdec_vp8_inst *inst)
169 {
170 inst->reg_base.top = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_TOP);
171 inst->reg_base.cm = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_CM);
172 inst->reg_base.hwd = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWD);
173 inst->reg_base.sys = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_SYS);
174 inst->reg_base.misc = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_MISC);
175 inst->reg_base.ld = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_LD);
176 inst->reg_base.hwb = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWB);
177 }
178
179 static void write_hw_segmentation_data(struct vdec_vp8_inst *inst)
180 {
181 int i, j;
182 u32 seg_id_addr;
183 u32 val;
184 void __iomem *cm = inst->reg_base.cm;
185 struct vdec_vp8_vsi *vsi = inst->vsi;
186
187 seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
188
189 for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) {
190 for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) {
191 val = (1 << 16) + ((seg_id_addr + i) << 2) + j;
192 writel(val, cm + VP8_HW_VLD_ADDR);
193
194 val = vsi->segment_buf[i][j];
195 writel(val, cm + VP8_HW_VLD_VALUE);
196 }
197 }
198 }
199
200 static void read_hw_segmentation_data(struct vdec_vp8_inst *inst)
201 {
202 int i, j;
203 u32 seg_id_addr;
204 u32 val;
205 void __iomem *cm = inst->reg_base.cm;
206 struct vdec_vp8_vsi *vsi = inst->vsi;
207
208 seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
209
210 for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) {
211 for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) {
212 val = ((seg_id_addr + i) << 2) + j;
213 writel(val, cm + VP8_HW_VLD_ADDR);
214
215 val = readl(cm + VP8_HW_VLD_VALUE);
216 vsi->segment_buf[i][j] = val;
217 }
218 }
219 }
220
221
222 static void enable_hw_rw_function(struct vdec_vp8_inst *inst)
223 {
224 u32 val = 0;
225 void __iomem *sys = inst->reg_base.sys;
226 void __iomem *misc = inst->reg_base.misc;
227 void __iomem *ld = inst->reg_base.ld;
228 void __iomem *hwb = inst->reg_base.hwb;
229 void __iomem *hwd = inst->reg_base.hwd;
230
231 writel(0x1, sys + VP8_RW_CKEN_SET);
232 writel(0x101, ld + VP8_WO_VLD_SRST);
233 writel(0x101, hwb + VP8_WO_VLD_SRST);
234
235 writel(1, sys);
236 val = readl(misc + VP8_RW_MISC_SRST);
237 writel((val & 0xFFFFFFFE), misc + VP8_RW_MISC_SRST);
238
239 writel(0x1, misc + VP8_RW_MISC_SYS_SEL);
240 writel(0x17F, misc + VP8_RW_MISC_SPEC_CON);
241 writel(0x71201100, misc + VP8_RW_MISC_FUNC_CON);
242 writel(0x0, ld + VP8_WO_VLD_SRST);
243 writel(0x0, hwb + VP8_WO_VLD_SRST);
244 writel(0x1, sys + VP8_RW_DCM_CON);
245 writel(0x1, misc + VP8_RW_MISC_DCM_CON);
246 writel(0x1, hwd + VP8_RW_VP8_CTRL);
247 }
248
249 static void store_dec_table(struct vdec_vp8_inst *inst)
250 {
251 int i, j;
252 u32 addr = 0, val = 0;
253 void __iomem *hwd = inst->reg_base.hwd;
254 u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET];
255
256 for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) {
257 writel(addr, hwd + VP8_BSASET);
258 for (j = 0; j < VP8_DEC_TABLE_UNIT ; j++) {
259 val = *p++;
260 writel(val, hwd + VP8_BSDSET);
261 }
262 addr += VP8_DEC_TABLE_RW_UNIT;
263 }
264 }
265
266 static void load_dec_table(struct vdec_vp8_inst *inst)
267 {
268 int i;
269 u32 addr = 0;
270 u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET];
271 void __iomem *hwd = inst->reg_base.hwd;
272
273 for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) {
274 writel(addr, hwd + VP8_BSASET);
275
276 *p++ = readl(hwd + VP8_BSDSET);
277 *p++ = readl(hwd + VP8_BSDSET);
278 *p++ = readl(hwd + VP8_BSDSET) & 0xFFFFFF;
279 addr += VP8_DEC_TABLE_RW_UNIT;
280 }
281 }
282
283 static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic)
284 {
285 *pic = inst->vsi->pic;
286
287 mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
288 pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
289 mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
290 pic->fb_sz[0], pic->fb_sz[1]);
291 }
292
293 static void vp8_dec_finish(struct vdec_vp8_inst *inst)
294 {
295 struct vdec_fb_node *node;
296 uint64_t prev_y_dma = inst->vsi->dec.prev_y_dma;
297
298 mtk_vcodec_debug(inst, "prev fb base dma=%llx", prev_y_dma);
299
300
301 if (prev_y_dma != 0) {
302 list_for_each_entry(node, &inst->fb_use_list, list) {
303 struct vdec_fb *fb = (struct vdec_fb *)node->fb;
304
305 if (prev_y_dma == (uint64_t)fb->base_y.dma_addr) {
306 list_move_tail(&node->list,
307 &inst->fb_free_list);
308 break;
309 }
310 }
311 }
312
313
314 node = list_first_entry(&inst->available_fb_node_list,
315 struct vdec_fb_node, list);
316 node->fb = inst->cur_fb;
317 list_move_tail(&node->list, &inst->fb_use_list);
318
319
320 if (inst->vsi->dec.show_frame) {
321 node = list_first_entry(&inst->available_fb_node_list,
322 struct vdec_fb_node, list);
323 node->fb = inst->cur_fb;
324 list_move_tail(&node->list, &inst->fb_disp_list);
325 }
326 }
327
328 static void move_fb_list_use_to_free(struct vdec_vp8_inst *inst)
329 {
330 struct vdec_fb_node *node, *tmp;
331
332 list_for_each_entry_safe(node, tmp, &inst->fb_use_list, list)
333 list_move_tail(&node->list, &inst->fb_free_list);
334 }
335
336 static void init_list(struct vdec_vp8_inst *inst)
337 {
338 int i;
339
340 INIT_LIST_HEAD(&inst->available_fb_node_list);
341 INIT_LIST_HEAD(&inst->fb_use_list);
342 INIT_LIST_HEAD(&inst->fb_free_list);
343 INIT_LIST_HEAD(&inst->fb_disp_list);
344
345 for (i = 0; i < ARRAY_SIZE(inst->dec_fb); i++) {
346 INIT_LIST_HEAD(&inst->dec_fb[i].list);
347 inst->dec_fb[i].fb = NULL;
348 list_add_tail(&inst->dec_fb[i].list,
349 &inst->available_fb_node_list);
350 }
351 }
352
353 static void add_fb_to_free_list(struct vdec_vp8_inst *inst, void *fb)
354 {
355 struct vdec_fb_node *node;
356
357 if (fb) {
358 node = list_first_entry(&inst->available_fb_node_list,
359 struct vdec_fb_node, list);
360 node->fb = fb;
361 list_move_tail(&node->list, &inst->fb_free_list);
362 }
363 }
364
365 static int alloc_working_buf(struct vdec_vp8_inst *inst)
366 {
367 int err;
368 struct mtk_vcodec_mem *mem = &inst->working_buf;
369
370 mem->size = VP8_WORKING_BUF_SZ;
371 err = mtk_vcodec_mem_alloc(inst->ctx, mem);
372 if (err) {
373 mtk_vcodec_err(inst, "Cannot allocate working buffer");
374 return err;
375 }
376
377 inst->vsi->dec.working_buf_dma = (uint64_t)mem->dma_addr;
378 return 0;
379 }
380
381 static void free_working_buf(struct vdec_vp8_inst *inst)
382 {
383 struct mtk_vcodec_mem *mem = &inst->working_buf;
384
385 if (mem->va)
386 mtk_vcodec_mem_free(inst->ctx, mem);
387
388 inst->vsi->dec.working_buf_dma = 0;
389 }
390
391 static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx)
392 {
393 struct vdec_vp8_inst *inst;
394 int err;
395
396 inst = kzalloc(sizeof(*inst), GFP_KERNEL);
397 if (!inst)
398 return -ENOMEM;
399
400 inst->ctx = ctx;
401
402 inst->vpu.id = IPI_VDEC_VP8;
403 inst->vpu.dev = ctx->dev->vpu_plat_dev;
404 inst->vpu.ctx = ctx;
405 inst->vpu.handler = vpu_dec_ipi_handler;
406
407 err = vpu_dec_init(&inst->vpu);
408 if (err) {
409 mtk_vcodec_err(inst, "vdec_vp8 init err=%d", err);
410 goto error_free_inst;
411 }
412
413 inst->vsi = (struct vdec_vp8_vsi *)inst->vpu.vsi;
414 init_list(inst);
415 err = alloc_working_buf(inst);
416 if (err)
417 goto error_deinit;
418
419 get_hw_reg_base(inst);
420 mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst);
421
422 ctx->drv_handle = inst;
423 return 0;
424
425 error_deinit:
426 vpu_dec_deinit(&inst->vpu);
427 error_free_inst:
428 kfree(inst);
429 return err;
430 }
431
432 static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
433 struct vdec_fb *fb, bool *res_chg)
434 {
435 struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
436 struct vdec_vp8_dec_info *dec = &inst->vsi->dec;
437 struct vdec_vpu_inst *vpu = &inst->vpu;
438 unsigned char *bs_va;
439 unsigned int data;
440 int err = 0;
441 uint64_t y_fb_dma;
442 uint64_t c_fb_dma;
443
444
445 if (bs == NULL) {
446 move_fb_list_use_to_free(inst);
447 return vpu_dec_reset(vpu);
448 }
449
450 y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
451 c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
452
453 mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx fb=%p",
454 inst->frm_cnt, y_fb_dma, c_fb_dma, fb);
455
456 inst->cur_fb = fb;
457 dec->bs_dma = (unsigned long)bs->dma_addr;
458 dec->bs_sz = bs->size;
459 dec->cur_y_fb_dma = y_fb_dma;
460 dec->cur_c_fb_dma = c_fb_dma;
461
462 mtk_vcodec_debug(inst, "\n + FRAME[%d] +\n", inst->frm_cnt);
463
464 write_hw_segmentation_data(inst);
465 enable_hw_rw_function(inst);
466 store_dec_table(inst);
467
468 bs_va = (unsigned char *)bs->va;
469
470
471 data = (*(bs_va + 9) << 24) | (*(bs_va + 8) << 16) |
472 (*(bs_va + 7) << 8) | *(bs_va + 6);
473 err = vpu_dec_start(vpu, &data, 1);
474 if (err) {
475 add_fb_to_free_list(inst, fb);
476 if (dec->wait_key_frame) {
477 mtk_vcodec_debug(inst, "wait key frame !");
478 return 0;
479 }
480
481 goto error;
482 }
483
484 if (dec->resolution_changed) {
485 mtk_vcodec_debug(inst, "- resolution_changed -");
486 *res_chg = true;
487 add_fb_to_free_list(inst, fb);
488 return 0;
489 }
490
491
492 mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED,
493 WAIT_INTR_TIMEOUT_MS);
494
495 if (inst->vsi->load_data)
496 load_dec_table(inst);
497
498 vp8_dec_finish(inst);
499 read_hw_segmentation_data(inst);
500
501 err = vpu_dec_end(vpu);
502 if (err)
503 goto error;
504
505 mtk_vcodec_debug(inst, "\n - FRAME[%d] - show=%d\n", inst->frm_cnt,
506 dec->show_frame);
507 inst->frm_cnt++;
508 *res_chg = false;
509 return 0;
510
511 error:
512 mtk_vcodec_err(inst, "\n - FRAME[%d] - err=%d\n", inst->frm_cnt, err);
513 return err;
514 }
515
516 static void get_disp_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
517 {
518 struct vdec_fb_node *node;
519 struct vdec_fb *fb;
520
521 node = list_first_entry_or_null(&inst->fb_disp_list,
522 struct vdec_fb_node, list);
523 if (node) {
524 list_move_tail(&node->list, &inst->available_fb_node_list);
525 fb = (struct vdec_fb *)node->fb;
526 fb->status |= FB_ST_DISPLAY;
527 mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d",
528 node->fb, fb->status);
529 } else {
530 fb = NULL;
531 mtk_vcodec_debug(inst, "[FB] there is no disp fb");
532 }
533
534 *out_fb = fb;
535 }
536
537 static void get_free_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
538 {
539 struct vdec_fb_node *node;
540 struct vdec_fb *fb;
541
542 node = list_first_entry_or_null(&inst->fb_free_list,
543 struct vdec_fb_node, list);
544 if (node) {
545 list_move_tail(&node->list, &inst->available_fb_node_list);
546 fb = (struct vdec_fb *)node->fb;
547 fb->status |= FB_ST_FREE;
548 mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d",
549 node->fb, fb->status);
550 } else {
551 fb = NULL;
552 mtk_vcodec_debug(inst, "[FB] there is no free fb");
553 }
554
555 *out_fb = fb;
556 }
557
558 static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_rect *cr)
559 {
560 cr->left = 0;
561 cr->top = 0;
562 cr->width = inst->vsi->pic.pic_w;
563 cr->height = inst->vsi->pic.pic_h;
564 mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d",
565 cr->left, cr->top, cr->width, cr->height);
566 }
567
568 static int vdec_vp8_get_param(void *h_vdec, enum vdec_get_param_type type,
569 void *out)
570 {
571 struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
572
573 switch (type) {
574 case GET_PARAM_DISP_FRAME_BUFFER:
575 get_disp_fb(inst, out);
576 break;
577
578 case GET_PARAM_FREE_FRAME_BUFFER:
579 get_free_fb(inst, out);
580 break;
581
582 case GET_PARAM_PIC_INFO:
583 get_pic_info(inst, out);
584 break;
585
586 case GET_PARAM_CROP_INFO:
587 get_crop_info(inst, out);
588 break;
589
590 case GET_PARAM_DPB_SIZE:
591 *((unsigned int *)out) = VP8_DPB_SIZE;
592 break;
593
594 default:
595 mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
596 return -EINVAL;
597 }
598
599 return 0;
600 }
601
602 static void vdec_vp8_deinit(void *h_vdec)
603 {
604 struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
605
606 mtk_vcodec_debug_enter(inst);
607
608 vpu_dec_deinit(&inst->vpu);
609 free_working_buf(inst);
610 kfree(inst);
611 }
612
613 const struct vdec_common_if vdec_vp8_if = {
614 .init = vdec_vp8_init,
615 .decode = vdec_vp8_decode,
616 .get_param = vdec_vp8_get_param,
617 .deinit = vdec_vp8_deinit,
618 };