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