summaryrefslogtreecommitdiff
path: root/drivers/frame_provider/decoder/mpeg4/vmpeg4.c (plain)
blob: b0a715a3fccf27d52346aeecf34d57bf0edf8584
1/*
2 * drivers/amlogic/amports/vmpeg4.c
3 *
4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17
18#define DEBUG
19#include <linux/kernel.h>
20#include <linux/types.h>
21#include <linux/errno.h>
22#include <linux/interrupt.h>
23#include <linux/timer.h>
24#include <linux/kfifo.h>
25#include <linux/platform_device.h>
26#include <linux/dma-mapping.h>
27#include <linux/amlogic/media/utils/amstream.h>
28#include <linux/amlogic/media/frame_sync/ptsserv.h>
29
30#include <linux/amlogic/media/vfm/vframe.h>
31#include <linux/amlogic/media/vfm/vframe_provider.h>
32#include <linux/amlogic/media/vfm/vframe_receiver.h>
33#include <linux/amlogic/media/canvas/canvas.h>
34
35#include <linux/amlogic/media/utils/vdec_reg.h>
36#include "vmpeg4.h"
37#include <linux/amlogic/media/registers/register.h>
38#include "../../../stream_input/amports/amports_priv.h"
39#include "../utils/decoder_mmu_box.h"
40#include "../utils/decoder_bmmu_box.h"
41#include <linux/amlogic/media/codec_mm/codec_mm.h>
42#include <linux/amlogic/media/codec_mm/configs.h>
43#include <linux/amlogic/tee.h>
44#include "../../../common/chips/decoder_cpu_ver_info.h"
45
46
47/* #define CONFIG_AM_VDEC_MPEG4_LOG */
48#ifdef CONFIG_AM_VDEC_MPEG4_LOG
49#define AMLOG
50#define LOG_LEVEL_VAR amlog_level_vmpeg4
51#define LOG_MASK_VAR amlog_mask_vmpeg4
52#define LOG_LEVEL_ERROR 0
53#define LOG_LEVEL_INFO 1
54#define LOG_LEVEL_DESC "0:ERROR, 1:INFO"
55#define LOG_MASK_PTS 0x01
56#define LOG_MASK_DESC "0x01:DEBUG_PTS"
57#endif
58
59#include <linux/amlogic/media/utils/amlog.h>
60
61MODULE_AMLOG(LOG_LEVEL_ERROR, 0, LOG_LEVEL_DESC, LOG_DEFAULT_MASK_DESC);
62
63#include "../utils/amvdec.h"
64#include "../utils/vdec.h"
65#include "../utils/firmware.h"
66
67#define DRIVER_NAME "amvdec_mpeg4"
68#define MODULE_NAME "amvdec_mpeg4"
69
70#define DEBUG_PTS
71
72/* /#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
73#define NV21
74/* /#endif */
75
76#define I_PICTURE 0
77#define P_PICTURE 1
78#define B_PICTURE 2
79
80#define ORI_BUFFER_START_ADDR 0x01000000
81
82#define INTERLACE_FLAG 0x80
83#define TOP_FIELD_FIRST_FLAG 0x40
84
85/* protocol registers */
86#define MP4_PIC_RATIO AV_SCRATCH_5
87#define MP4_RATE AV_SCRATCH_3
88#define MP4_ERR_COUNT AV_SCRATCH_6
89#define MP4_PIC_WH AV_SCRATCH_7
90#define MREG_BUFFERIN AV_SCRATCH_8
91#define MREG_BUFFEROUT AV_SCRATCH_9
92#define MP4_NOT_CODED_CNT AV_SCRATCH_A
93#define MP4_VOP_TIME_INC AV_SCRATCH_B
94#define MP4_OFFSET_REG AV_SCRATCH_C
95#define MP4_SYS_RATE AV_SCRATCH_E
96#define MEM_OFFSET_REG AV_SCRATCH_F
97
98#define PARC_FORBIDDEN 0
99#define PARC_SQUARE 1
100#define PARC_CIF 2
101#define PARC_10_11 3
102#define PARC_16_11 4
103#define PARC_40_33 5
104#define PARC_RESERVED 6
105/* values between 6 and 14 are reserved */
106#define PARC_EXTENDED 15
107
108#define VF_POOL_SIZE 32
109#define DECODE_BUFFER_NUM_MAX 8
110#define PUT_INTERVAL (HZ/100)
111#define WORKSPACE_SIZE (1 * SZ_1M)
112#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1)
113#define DCAC_BUFF_START_IP 0x02b00000
114
115
116#define RATE_DETECT_COUNT 5
117#define DURATION_UNIT 96000
118#define PTS_UNIT 90000
119
120#define DUR2PTS(x) ((x) - ((x) >> 4))
121
122#define MAX_MPEG4_SUPPORT_SIZE (1920*1088)
123
124static struct vframe_s *vmpeg_vf_peek(void *);
125static struct vframe_s *vmpeg_vf_get(void *);
126static void vmpeg_vf_put(struct vframe_s *, void *);
127static int vmpeg_vf_states(struct vframe_states *states, void *);
128static int vmpeg_event_cb(int type, void *data, void *private_data);
129
130static int vmpeg4_prot_init(void);
131static void vmpeg4_local_init(void);
132
133static const char vmpeg4_dec_id[] = "vmpeg4-dev";
134
135#define PROVIDER_NAME "decoder.mpeg4"
136
137/*
138 *int query_video_status(int type, int *value);
139 */
140static const struct vframe_operations_s vmpeg_vf_provider = {
141 .peek = vmpeg_vf_peek,
142 .get = vmpeg_vf_get,
143 .put = vmpeg_vf_put,
144 .event_cb = vmpeg_event_cb,
145 .vf_states = vmpeg_vf_states,
146};
147static void *mm_blk_handle;
148static struct vframe_provider_s vmpeg_vf_prov;
149
150static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
151static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
152static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE);
153
154static struct vframe_s vfpool[VF_POOL_SIZE];
155static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
156static u32 frame_width, frame_height, frame_dur, frame_prog;
157static u32 saved_resolution;
158static struct timer_list recycle_timer;
159static u32 stat;
160static u32 buf_size = 32 * 1024 * 1024;
161static u32 buf_offset;
162static u32 vmpeg4_ratio;
163static u64 vmpeg4_ratio64;
164static u32 rate_detect;
165static u32 vmpeg4_rotation;
166static u32 fr_hint_status;
167
168static u32 total_frame;
169static u32 last_vop_time_inc, last_duration;
170static u32 last_anch_pts, vop_time_inc_since_last_anch,
171 frame_num_since_last_anch;
172static u64 last_anch_pts_us64;
173static struct vdec_info *gvs;
174
175#ifdef CONFIG_AM_VDEC_MPEG4_LOG
176u32 pts_hit, pts_missed, pts_i_hit, pts_i_missed;
177#endif
178
179static struct work_struct reset_work;
180static struct work_struct notify_work;
181static struct work_struct set_clk_work;
182static bool is_reset;
183
184static DEFINE_SPINLOCK(lock);
185
186static struct dec_sysinfo vmpeg4_amstream_dec_info;
187
188static unsigned char aspect_ratio_table[16] = {
189 PARC_FORBIDDEN,
190 PARC_SQUARE,
191 PARC_CIF,
192 PARC_10_11,
193 PARC_16_11,
194 PARC_40_33,
195 PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
196 PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
197 PARC_RESERVED, PARC_EXTENDED
198};
199
200static inline u32 index2canvas(u32 index)
201{
202 const u32 canvas_tab[8] = {
203#ifdef NV21
204 0x010100, 0x030302, 0x050504, 0x070706,
205 0x090908, 0x0b0b0a, 0x0d0d0c, 0x0f0f0e
206#else
207 0x020100, 0x050403, 0x080706, 0x0b0a09,
208 0x0e0d0c, 0x11100f, 0x141312, 0x171615
209#endif
210 };
211
212 return canvas_tab[index];
213}
214
215static void set_aspect_ratio(struct vframe_s *vf, unsigned int pixel_ratio)
216{
217 int ar = 0;
218 unsigned int num = 0;
219 unsigned int den = 0;
220
221 if (vmpeg4_ratio64 != 0) {
222 num = vmpeg4_ratio64 >> 32;
223 den = vmpeg4_ratio64 & 0xffffffff;
224 } else {
225 num = vmpeg4_ratio >> 16;
226 den = vmpeg4_ratio & 0xffff;
227
228 }
229 if ((num == 0) || (den == 0)) {
230 num = 1;
231 den = 1;
232 }
233
234 if (vmpeg4_ratio == 0) {
235 vf->ratio_control |= (0x90 << DISP_RATIO_ASPECT_RATIO_BIT);
236 /* always stretch to 16:9 */
237 } else if (pixel_ratio > 0x0f) {
238 num = (pixel_ratio >> 8) *
239 vmpeg4_amstream_dec_info.width * num;
240 ar = div_u64((pixel_ratio & 0xff) *
241 vmpeg4_amstream_dec_info.height * den * 0x100ULL +
242 (num >> 1), num);
243 } else {
244 switch (aspect_ratio_table[pixel_ratio]) {
245 case 0:
246 num = vmpeg4_amstream_dec_info.width * num;
247 ar = (vmpeg4_amstream_dec_info.height * den * 0x100 +
248 (num >> 1)) / num;
249 break;
250 case 1:
251 num = vf->width * num;
252 ar = (vf->height * den * 0x100 + (num >> 1)) / num;
253 break;
254 case 2:
255 num = (vf->width * 12) * num;
256 ar = (vf->height * den * 0x100 * 11 +
257 ((num) >> 1)) / num;
258 break;
259 case 3:
260 num = (vf->width * 10) * num;
261 ar = (vf->height * den * 0x100 * 11 + (num >> 1)) /
262 num;
263 break;
264 case 4:
265 num = (vf->width * 16) * num;
266 ar = (vf->height * den * 0x100 * 11 + (num >> 1)) /
267 num;
268 break;
269 case 5:
270 num = (vf->width * 40) * num;
271 ar = (vf->height * den * 0x100 * 33 + (num >> 1)) /
272 num;
273 break;
274 default:
275 num = vf->width * num;
276 ar = (vf->height * den * 0x100 + (num >> 1)) / num;
277 break;
278 }
279 }
280
281 ar = min(ar, DISP_RATIO_ASPECT_RATIO_MAX);
282
283 vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
284}
285
286static irqreturn_t vmpeg4_isr(int irq, void *dev_id)
287{
288 u32 reg;
289 struct vframe_s *vf = NULL;
290 u32 picture_type;
291 u32 buffer_index;
292 u32 pts, pts_valid = 0, offset = 0;
293 u64 pts_us64 = 0;
294 u32 rate, vop_time_inc, repeat_cnt, duration = 3200;
295 u32 frame_size;
296
297 reg = READ_VREG(MREG_BUFFEROUT);
298
299 if (reg) {
300 buffer_index = reg & 0x7;
301 picture_type = (reg >> 3) & 7;
302 rate = READ_VREG(MP4_RATE);
303 repeat_cnt = READ_VREG(MP4_NOT_CODED_CNT);
304 vop_time_inc = READ_VREG(MP4_VOP_TIME_INC);
305
306 if (buffer_index >= DECODE_BUFFER_NUM_MAX) {
307 pr_err("fatal error, invalid buffer index.");
308 return IRQ_HANDLED;
309 }
310
311 if (vmpeg4_amstream_dec_info.width == 0) {
312 vmpeg4_amstream_dec_info.width =
313 READ_VREG(MP4_PIC_WH) >> 16;
314 }
315#if 0
316 else {
317 pr_info("info width = %d, ucode width = %d\n",
318 vmpeg4_amstream_dec_info.width,
319 READ_VREG(MP4_PIC_WH) >> 16);
320 }
321#endif
322
323 if (vmpeg4_amstream_dec_info.height == 0) {
324 vmpeg4_amstream_dec_info.height =
325 READ_VREG(MP4_PIC_WH) & 0xffff;
326 }
327#if 0
328 else {
329 pr_info("info height = %d, ucode height = %d\n",
330 vmpeg4_amstream_dec_info.height,
331 READ_VREG(MP4_PIC_WH) & 0xffff);
332 }
333#endif
334 if (vmpeg4_amstream_dec_info.rate == 0
335 || vmpeg4_amstream_dec_info.rate > 96000) {
336 /* if ((rate >> 16) != 0) { */
337 if ((rate & 0xffff) != 0 && (rate >> 16) != 0) {
338 vmpeg4_amstream_dec_info.rate =
339 (rate >> 16) * DURATION_UNIT /
340 (rate & 0xffff);
341 duration = vmpeg4_amstream_dec_info.rate;
342 if (fr_hint_status == VDEC_NEED_HINT) {
343 schedule_work(&notify_work);
344 fr_hint_status = VDEC_HINTED;
345 }
346 } else if (rate_detect < RATE_DETECT_COUNT) {
347 if (vop_time_inc < last_vop_time_inc) {
348 duration =
349 vop_time_inc + rate -
350 last_vop_time_inc;
351 } else {
352 duration =
353 vop_time_inc - last_vop_time_inc;
354 }
355
356 if (duration == last_duration) {
357 rate_detect++;
358 if (rate_detect >= RATE_DETECT_COUNT) {
359 vmpeg4_amstream_dec_info.rate =
360 duration * DURATION_UNIT /
361 rate;
362 duration =
363 vmpeg4_amstream_dec_info.rate;
364 }
365 } else
366 rate_detect = 0;
367
368 last_duration = duration;
369 }
370 } else {
371 duration = vmpeg4_amstream_dec_info.rate;
372#if 0
373 pr_info("info rate = %d, ucode rate = 0x%x:0x%x\n",
374 vmpeg4_amstream_dec_info.rate,
375 READ_VREG(MP4_RATE), vop_time_inc);
376#endif
377 }
378
379 if ((picture_type == I_PICTURE) ||
380 (picture_type == P_PICTURE)) {
381 offset = READ_VREG(MP4_OFFSET_REG);
382 /*2500-->3000,because some mpeg4
383 *video may checkout failed;
384 *may have av sync problem.can changed small later.
385 *263 may need small?
386 */
387 if (pts_lookup_offset_us64
388 (PTS_TYPE_VIDEO, offset, &pts,
389 &frame_size, 3000,
390 &pts_us64) == 0) {
391 pts_valid = 1;
392 last_anch_pts = pts;
393 last_anch_pts_us64 = pts_us64;
394#ifdef CONFIG_AM_VDEC_MPEG4_LOG
395 pts_hit++;
396#endif
397 } else {
398#ifdef CONFIG_AM_VDEC_MPEG4_LOG
399 pts_missed++;
400#endif
401 }
402#ifdef CONFIG_AM_VDEC_MPEG4_LOG
403 amlog_mask(LOG_MASK_PTS,
404 "I offset 0x%x, pts_valid %d pts=0x%x\n",
405 offset, pts_valid, pts);
406#endif
407 }
408
409 if (pts_valid) {
410 last_anch_pts = pts;
411 last_anch_pts_us64 = pts_us64;
412 frame_num_since_last_anch = 0;
413 vop_time_inc_since_last_anch = 0;
414 } else {
415 pts = last_anch_pts;
416 pts_us64 = last_anch_pts_us64;
417
418 if ((rate != 0) && ((rate >> 16) == 0)
419 && vmpeg4_amstream_dec_info.rate == 0) {
420 /* variable PTS rate */
421 /*bug on variable pts calc,
422 *do as dixed vop first if we
423 *have rate setting before.
424 */
425 if (vop_time_inc > last_vop_time_inc) {
426 vop_time_inc_since_last_anch +=
427 vop_time_inc - last_vop_time_inc;
428 } else {
429 vop_time_inc_since_last_anch +=
430 vop_time_inc + rate -
431 last_vop_time_inc;
432 }
433
434 pts += vop_time_inc_since_last_anch *
435 PTS_UNIT / rate;
436 pts_us64 += (vop_time_inc_since_last_anch *
437 PTS_UNIT / rate) * 100 / 9;
438
439 if (vop_time_inc_since_last_anch > (1 << 14)) {
440 /* avoid overflow */
441 last_anch_pts = pts;
442 last_anch_pts_us64 = pts_us64;
443 vop_time_inc_since_last_anch = 0;
444 }
445 } else {
446 /* fixed VOP rate */
447 frame_num_since_last_anch++;
448 pts += DUR2PTS(frame_num_since_last_anch *
449 vmpeg4_amstream_dec_info.rate);
450 pts_us64 += DUR2PTS(frame_num_since_last_anch *
451 vmpeg4_amstream_dec_info.rate) *
452 100 / 9;
453
454 if (frame_num_since_last_anch > (1 << 15)) {
455 /* avoid overflow */
456 last_anch_pts = pts;
457 last_anch_pts_us64 = pts_us64;
458 frame_num_since_last_anch = 0;
459 }
460 }
461 }
462
463 if (reg & INTERLACE_FLAG) { /* interlace */
464 if (kfifo_get(&newframe_q, &vf) == 0) {
465 printk
466 ("fatal error, no available buffer slot.");
467 return IRQ_HANDLED;
468 }
469 vf->signal_type = 0;
470 vf->index = buffer_index;
471 vf->width = vmpeg4_amstream_dec_info.width;
472 vf->height = vmpeg4_amstream_dec_info.height;
473 vf->bufWidth = 1920;
474 vf->flag = 0;
475 vf->orientation = vmpeg4_rotation;
476 vf->pts = pts;
477 vf->pts_us64 = pts_us64;
478 vf->duration = duration >> 1;
479 vf->duration_pulldown = 0;
480 vf->type = (reg & TOP_FIELD_FIRST_FLAG) ?
481 VIDTYPE_INTERLACE_TOP :
482 VIDTYPE_INTERLACE_BOTTOM;
483#ifdef NV21
484 vf->type |= VIDTYPE_VIU_NV21;
485#endif
486 vf->canvas0Addr = vf->canvas1Addr =
487 index2canvas(buffer_index);
488 vf->type_original = vf->type;
489
490 set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO));
491
492 vfbuf_use[buffer_index]++;
493 vf->mem_handle =
494 decoder_bmmu_box_get_mem_handle(
495 mm_blk_handle,
496 buffer_index);
497
498 kfifo_put(&display_q, (const struct vframe_s *)vf);
499 ATRACE_COUNTER(MODULE_NAME, vf->pts);
500
501 vf_notify_receiver(PROVIDER_NAME,
502 VFRAME_EVENT_PROVIDER_VFRAME_READY,
503 NULL);
504
505 if (kfifo_get(&newframe_q, &vf) == 0) {
506 printk(
507 "fatal error, no available buffer slot.");
508 return IRQ_HANDLED;
509 }
510 vf->signal_type = 0;
511 vf->index = buffer_index;
512 vf->width = vmpeg4_amstream_dec_info.width;
513 vf->height = vmpeg4_amstream_dec_info.height;
514 vf->bufWidth = 1920;
515 vf->flag = 0;
516 vf->orientation = vmpeg4_rotation;
517
518 vf->pts = 0;
519 vf->pts_us64 = 0;
520 vf->duration = duration >> 1;
521
522 vf->duration_pulldown = 0;
523 vf->type = (reg & TOP_FIELD_FIRST_FLAG) ?
524 VIDTYPE_INTERLACE_BOTTOM : VIDTYPE_INTERLACE_TOP;
525#ifdef NV21
526 vf->type |= VIDTYPE_VIU_NV21;
527#endif
528 vf->canvas0Addr = vf->canvas1Addr =
529 index2canvas(buffer_index);
530 vf->type_original = vf->type;
531
532 set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO));
533
534 vfbuf_use[buffer_index]++;
535 vf->mem_handle =
536 decoder_bmmu_box_get_mem_handle(
537 mm_blk_handle,
538 buffer_index);
539
540 amlog_mask(LOG_MASK_PTS,
541 "[%s:%d] [inte] dur=0x%x rate=%d picture_type=%d\n",
542 __func__, __LINE__, vf->duration,
543 vmpeg4_amstream_dec_info.rate, picture_type);
544
545 kfifo_put(&display_q, (const struct vframe_s *)vf);
546 ATRACE_COUNTER(MODULE_NAME, vf->pts);
547
548 vf_notify_receiver(PROVIDER_NAME,
549 VFRAME_EVENT_PROVIDER_VFRAME_READY,
550 NULL);
551
552 } else { /* progressive */
553 if (kfifo_get(&newframe_q, &vf) == 0) {
554 printk
555 ("fatal error, no available buffer slot.");
556 return IRQ_HANDLED;
557 }
558 vf->signal_type = 0;
559 vf->index = buffer_index;
560 vf->width = vmpeg4_amstream_dec_info.width;
561 vf->height = vmpeg4_amstream_dec_info.height;
562 vf->bufWidth = 1920;
563 vf->flag = 0;
564 vf->orientation = vmpeg4_rotation;
565 vf->pts = pts;
566 vf->pts_us64 = pts_us64;
567 vf->duration = duration;
568 vf->duration_pulldown = repeat_cnt * duration;
569#ifdef NV21
570 vf->type =
571 VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
572 VIDTYPE_VIU_NV21;
573#else
574 vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
575#endif
576 vf->canvas0Addr = vf->canvas1Addr =
577 index2canvas(buffer_index);
578 vf->type_original = vf->type;
579
580 set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO));
581
582 amlog_mask(LOG_MASK_PTS,
583 "[%s:%d] [prog] dur=0x%x rate=%d picture_type=%d\n",
584 __func__, __LINE__, vf->duration,
585 vmpeg4_amstream_dec_info.rate, picture_type);
586
587 vfbuf_use[buffer_index]++;
588 vf->mem_handle =
589 decoder_bmmu_box_get_mem_handle(
590 mm_blk_handle,
591 buffer_index);
592
593 kfifo_put(&display_q, (const struct vframe_s *)vf);
594 ATRACE_COUNTER(MODULE_NAME, vf->pts);
595
596 vf_notify_receiver(PROVIDER_NAME,
597 VFRAME_EVENT_PROVIDER_VFRAME_READY,
598 NULL);
599 }
600
601 total_frame += repeat_cnt + 1;
602
603 WRITE_VREG(MREG_BUFFEROUT, 0);
604
605 last_vop_time_inc = vop_time_inc;
606
607 /*count info*/
608 gvs->frame_dur = duration;
609 vdec_count_info(gvs, 0, offset);
610 }
611
612 WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
613
614 return IRQ_HANDLED;
615}
616
617static struct vframe_s *vmpeg_vf_peek(void *op_arg)
618{
619 struct vframe_s *vf;
620
621 if (kfifo_peek(&display_q, &vf))
622 return vf;
623
624 return NULL;
625}
626
627static struct vframe_s *vmpeg_vf_get(void *op_arg)
628{
629 struct vframe_s *vf;
630
631 if (kfifo_get(&display_q, &vf))
632 return vf;
633
634 return NULL;
635}
636
637static void vmpeg_vf_put(struct vframe_s *vf, void *op_arg)
638{
639 kfifo_put(&recycle_q, (const struct vframe_s *)vf);
640}
641
642static int vmpeg_event_cb(int type, void *data, void *private_data)
643{
644 if (type & VFRAME_EVENT_RECEIVER_RESET) {
645 unsigned long flags;
646
647 amvdec_stop();
648#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
649 vf_light_unreg_provider(&vmpeg_vf_prov);
650#endif
651 spin_lock_irqsave(&lock, flags);
652 vmpeg4_local_init();
653 vmpeg4_prot_init();
654 spin_unlock_irqrestore(&lock, flags);
655#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
656 vf_reg_provider(&vmpeg_vf_prov);
657#endif
658 amvdec_start();
659 }
660 return 0;
661}
662
663static int vmpeg_vf_states(struct vframe_states *states, void *op_arg)
664{
665 unsigned long flags;
666
667 spin_lock_irqsave(&lock, flags);
668
669 states->vf_pool_size = VF_POOL_SIZE;
670 states->buf_free_num = kfifo_len(&newframe_q);
671 states->buf_avail_num = kfifo_len(&display_q);
672 states->buf_recycle_num = kfifo_len(&recycle_q);
673
674 spin_unlock_irqrestore(&lock, flags);
675
676 return 0;
677}
678
679static void vmpeg4_notify_work(struct work_struct *work)
680{
681 pr_info("frame duration changed %d\n", vmpeg4_amstream_dec_info.rate);
682 vf_notify_receiver(PROVIDER_NAME,
683 VFRAME_EVENT_PROVIDER_FR_HINT,
684 (void *)
685 ((unsigned long)
686 vmpeg4_amstream_dec_info.rate));
687 return;
688}
689
690static void reset_do_work(struct work_struct *work)
691{
692 unsigned long flags;
693
694 amvdec_stop();
695#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
696 vf_light_unreg_provider(&vmpeg_vf_prov);
697#endif
698 spin_lock_irqsave(&lock, flags);
699 vmpeg4_local_init();
700 vmpeg4_prot_init();
701 spin_unlock_irqrestore(&lock, flags);
702#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
703 vf_reg_provider(&vmpeg_vf_prov);
704#endif
705 amvdec_start();
706}
707
708static void vmpeg4_set_clk(struct work_struct *work)
709{
710 int fps = 96000 / frame_dur;
711
712 saved_resolution = frame_width * frame_height * fps;
713 vdec_source_changed(VFORMAT_MPEG4,
714 frame_width, frame_height, fps);
715}
716
717static void vmpeg_put_timer_func(unsigned long arg)
718{
719 struct timer_list *timer = (struct timer_list *)arg;
720
721 while (!kfifo_is_empty(&recycle_q) && (READ_VREG(MREG_BUFFERIN) == 0)) {
722 struct vframe_s *vf;
723
724 if (kfifo_get(&recycle_q, &vf)) {
725 if ((vf->index < DECODE_BUFFER_NUM_MAX)
726 && (--vfbuf_use[vf->index] == 0)) {
727 WRITE_VREG(MREG_BUFFERIN, ~(1 << vf->index));
728 vf->index = DECODE_BUFFER_NUM_MAX;
729 }
730 kfifo_put(&newframe_q, (const struct vframe_s *)vf);
731 }
732 }
733
734 if (frame_dur > 0 && saved_resolution !=
735 frame_width * frame_height * (96000 / frame_dur))
736 schedule_work(&set_clk_work);
737
738 if (READ_VREG(AV_SCRATCH_L)) {
739 pr_info("mpeg4 fatal error happened,need reset !!\n");
740 schedule_work(&reset_work);
741 }
742
743
744 timer->expires = jiffies + PUT_INTERVAL;
745
746 add_timer(timer);
747}
748
749int vmpeg4_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
750{
751 if (!(stat & STAT_VDEC_RUN))
752 return -1;
753
754 vstatus->frame_width = vmpeg4_amstream_dec_info.width;
755 vstatus->frame_height = vmpeg4_amstream_dec_info.height;
756 if (0 != vmpeg4_amstream_dec_info.rate)
757 vstatus->frame_rate =
758 DURATION_UNIT / vmpeg4_amstream_dec_info.rate;
759 else
760 vstatus->frame_rate = -1;
761 vstatus->error_count = READ_VREG(MP4_ERR_COUNT);
762 vstatus->status = stat;
763 vstatus->bit_rate = gvs->bit_rate;
764 vstatus->frame_dur = frame_dur;
765 vstatus->frame_data = gvs->frame_data;
766 vstatus->total_data = gvs->total_data;
767 vstatus->frame_count = gvs->frame_count;
768 vstatus->error_frame_count = gvs->error_frame_count;
769 vstatus->drop_frame_count = gvs->drop_frame_count;
770 vstatus->total_data = gvs->total_data;
771 vstatus->samp_cnt = gvs->samp_cnt;
772 vstatus->offset = gvs->offset;
773 snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
774 "%s", DRIVER_NAME);
775
776 return 0;
777}
778
779int vmpeg4_set_isreset(struct vdec_s *vdec, int isreset)
780{
781 is_reset = isreset;
782 return 0;
783}
784
785static int vmpeg4_vdec_info_init(void)
786{
787 gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL);
788 if (NULL == gvs) {
789 pr_info("the struct of vdec status malloc failed.\n");
790 return -ENOMEM;
791 }
792 return 0;
793}
794
795/****************************************/
796static int vmpeg4_canvas_init(void)
797{
798 int i, ret;
799 u32 canvas_width, canvas_height;
800 unsigned long buf_start;
801 u32 alloc_size, decbuf_size, decbuf_y_size, decbuf_uv_size;
802
803 if (buf_size <= 0x00400000) {
804 /* SD only */
805 canvas_width = 768;
806 canvas_height = 576;
807 decbuf_y_size = 0x80000;
808 decbuf_uv_size = 0x20000;
809 decbuf_size = 0x100000;
810 } else {
811 int w = vmpeg4_amstream_dec_info.width;
812 int h = vmpeg4_amstream_dec_info.height;
813 int align_w, align_h;
814 int max, min;
815
816 align_w = ALIGN(w, 64);
817 align_h = ALIGN(h, 64);
818 if (align_w > align_h) {
819 max = align_w;
820 min = align_h;
821 } else {
822 max = align_h;
823 min = align_w;
824 }
825 /* HD & SD */
826 if ((max > 1920 || min > 1088) &&
827 ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <=
828 buf_size) {
829 canvas_width = align_w;
830 canvas_height = align_h;
831 decbuf_y_size = ALIGN(align_w * align_h, SZ_64K);
832 decbuf_uv_size = ALIGN(align_w * align_h/4, SZ_64K);
833 decbuf_size = ALIGN(align_w * align_h * 3/2, SZ_64K);
834 } else { /*1080p*/
835 if (h > w) {
836 canvas_width = 1088;
837 canvas_height = 1920;
838 } else {
839 canvas_width = 1920;
840 canvas_height = 1088;
841 }
842 decbuf_y_size = 0x200000;
843 decbuf_uv_size = 0x80000;
844 decbuf_size = 0x300000;
845 }
846 }
847
848 for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) {
849 /* workspace mem */
850 if (i == (MAX_BMMU_BUFFER_NUM - 1))
851 alloc_size = WORKSPACE_SIZE;
852 else
853 alloc_size = decbuf_size;
854
855 ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i,
856 alloc_size, DRIVER_NAME, &buf_start);
857 if (ret < 0)
858 return ret;
859 if (i == (MAX_BMMU_BUFFER_NUM - 1)) {
860 buf_offset = buf_start - DCAC_BUFF_START_IP;
861 continue;
862 }
863
864
865#ifdef NV21
866 canvas_config(2 * i + 0,
867 buf_start,
868 canvas_width, canvas_height,
869 CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
870 canvas_config(2 * i + 1,
871 buf_start +
872 decbuf_y_size, canvas_width,
873 canvas_height / 2, CANVAS_ADDR_NOWRAP,
874 CANVAS_BLKMODE_32X32);
875#else
876 canvas_config(3 * i + 0,
877 buf_start,
878 canvas_width, canvas_height,
879 CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
880 canvas_config(3 * i + 1,
881 buf_start +
882 decbuf_y_size, canvas_width / 2,
883 canvas_height / 2, CANVAS_ADDR_NOWRAP,
884 CANVAS_BLKMODE_32X32);
885 canvas_config(3 * i + 2,
886 buf_start +
887 decbuf_y_size + decbuf_uv_size,
888 canvas_width / 2, canvas_height / 2,
889 CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
890#endif
891
892 }
893 return 0;
894}
895
896static int vmpeg4_prot_init(void)
897{
898 int r;
899#if 1 /* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
900 WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
901 WRITE_VREG(DOS_SW_RESET0, 0);
902#else
903 WRITE_RESET_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
904#endif
905
906 r = vmpeg4_canvas_init();
907
908 /* index v << 16 | u << 8 | y */
909#ifdef NV21
910 WRITE_VREG(AV_SCRATCH_0, 0x010100);
911 WRITE_VREG(AV_SCRATCH_1, 0x030302);
912 WRITE_VREG(AV_SCRATCH_2, 0x050504);
913 WRITE_VREG(AV_SCRATCH_3, 0x070706);
914 WRITE_VREG(AV_SCRATCH_G, 0x090908);
915 WRITE_VREG(AV_SCRATCH_H, 0x0b0b0a);
916 WRITE_VREG(AV_SCRATCH_I, 0x0d0d0c);
917 WRITE_VREG(AV_SCRATCH_J, 0x0f0f0e);
918#else
919 WRITE_VREG(AV_SCRATCH_0, 0x020100);
920 WRITE_VREG(AV_SCRATCH_1, 0x050403);
921 WRITE_VREG(AV_SCRATCH_2, 0x080706);
922 WRITE_VREG(AV_SCRATCH_3, 0x0b0a09);
923 WRITE_VREG(AV_SCRATCH_G, 0x0e0d0c);
924 WRITE_VREG(AV_SCRATCH_H, 0x11100f);
925 WRITE_VREG(AV_SCRATCH_I, 0x141312);
926 WRITE_VREG(AV_SCRATCH_J, 0x171615);
927#endif
928 WRITE_VREG(AV_SCRATCH_L, 0);/*clearfatal error flag*/
929
930 /* notify ucode the buffer offset */
931 WRITE_VREG(AV_SCRATCH_F, buf_offset);
932
933 /* disable PSCALE for hardware sharing */
934 WRITE_VREG(PSCALE_CTRL, 0);
935
936 /* clear repeat count */
937 WRITE_VREG(MP4_NOT_CODED_CNT, 0);
938
939 WRITE_VREG(MREG_BUFFERIN, 0);
940 WRITE_VREG(MREG_BUFFEROUT, 0);
941
942 /* clear mailbox interrupt */
943 WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
944
945 /* enable mailbox interrupt */
946 WRITE_VREG(ASSIST_MBOX1_MASK, 1);
947
948
949
950#ifdef NV21
951 SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
952#endif
953
954#if 1/* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
955 pr_debug("mpeg4 meson8 prot init\n");
956 WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa);
957#endif
958
959 WRITE_VREG(MP4_PIC_WH, (vmpeg4_amstream_dec_info.
960 width << 16) | vmpeg4_amstream_dec_info.height);
961 WRITE_VREG(MP4_SYS_RATE, vmpeg4_amstream_dec_info.rate);
962 return r;
963}
964
965static void vmpeg4_local_init(void)
966{
967 int i;
968
969 vmpeg4_ratio = vmpeg4_amstream_dec_info.ratio;
970
971 vmpeg4_ratio64 = vmpeg4_amstream_dec_info.ratio64;
972
973 vmpeg4_rotation =
974 (((unsigned long) vmpeg4_amstream_dec_info.param)
975 >> 16) & 0xffff;
976
977 frame_width = frame_height = frame_dur = frame_prog = 0;
978
979 total_frame = 0;
980 saved_resolution = 0;
981 last_anch_pts = 0;
982
983 last_anch_pts_us64 = 0;
984
985 last_vop_time_inc = last_duration = 0;
986
987 vop_time_inc_since_last_anch = 0;
988
989 frame_num_since_last_anch = 0;
990
991#ifdef CONFIG_AM_VDEC_MPEG4_LOG
992 pts_hit = pts_missed = pts_i_hit = pts_i_missed = 0;
993#endif
994
995 for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
996 vfbuf_use[i] = 0;
997
998 INIT_KFIFO(display_q);
999 INIT_KFIFO(recycle_q);
1000 INIT_KFIFO(newframe_q);
1001
1002 for (i = 0; i < VF_POOL_SIZE; i++) {
1003 const struct vframe_s *vf = &vfpool[i];
1004
1005 vfpool[i].index = DECODE_BUFFER_NUM_MAX;
1006 kfifo_put(&newframe_q, (const struct vframe_s *)vf);
1007 }
1008 if (mm_blk_handle) {
1009 decoder_bmmu_box_free(mm_blk_handle);
1010 mm_blk_handle = NULL;
1011 }
1012
1013 mm_blk_handle = decoder_bmmu_box_alloc_box(
1014 DRIVER_NAME,
1015 0,
1016 MAX_BMMU_BUFFER_NUM,
1017 4 + PAGE_SHIFT,
1018 CODEC_MM_FLAGS_CMA_CLEAR |
1019 CODEC_MM_FLAGS_FOR_VDECODER);
1020}
1021
1022static s32 vmpeg4_init(void)
1023{
1024 int trickmode_fffb = 0;
1025 int size = -1, ret = -1;
1026 char fw_name[32] = {0};
1027 char *buf = vmalloc(0x1000 * 16);
1028
1029 if (IS_ERR_OR_NULL(buf))
1030 return -ENOMEM;
1031 amlog_level(LOG_LEVEL_INFO, "vmpeg4_init\n");
1032
1033 if (vmpeg4_amstream_dec_info.format ==
1034 VIDEO_DEC_FORMAT_MPEG4_5) {
1035 size = get_firmware_data(VIDEO_DEC_MPEG4_5, buf);
1036 strncpy(fw_name, "vmpeg4_mc_5", sizeof(fw_name));
1037
1038 amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_MPEG4_5\n");
1039 } else if (vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_H263) {
1040 size = get_firmware_data(VIDEO_DEC_H263, buf);
1041 strncpy(fw_name, "h263_mc", sizeof(fw_name));
1042
1043 pr_info("load VIDEO_DEC_FORMAT_H263\n");
1044 } else
1045 pr_err("unsupport mpeg4 sub format %d\n",
1046 vmpeg4_amstream_dec_info.format);
1047
1048 if (size < 0) {
1049 pr_err("get firmware fail.");
1050 vfree(buf);
1051 return -1;
1052 }
1053
1054 ret = amvdec_loadmc_ex(VFORMAT_MPEG4, fw_name, buf);
1055 if (ret < 0) {
1056 amvdec_disable();
1057 vfree(buf);
1058 pr_err("%s: the %s fw loading failed, err: %x\n",
1059 fw_name, tee_enabled() ? "TEE" : "local", ret);
1060 return -EBUSY;
1061 }
1062
1063 vfree(buf);
1064 stat |= STAT_MC_LOAD;
1065 query_video_status(0, &trickmode_fffb);
1066
1067 init_timer(&recycle_timer);
1068 stat |= STAT_TIMER_INIT;
1069
1070 if (vdec_request_irq(VDEC_IRQ_1, vmpeg4_isr,
1071 "vmpeg4-irq", (void *)vmpeg4_dec_id)) {
1072 amlog_level(LOG_LEVEL_ERROR, "vmpeg4 irq register error.\n");
1073 return -ENOENT;
1074 }
1075 stat |= STAT_ISR_REG;
1076 vmpeg4_local_init();
1077 /* enable AMRISC side protocol */
1078 ret = vmpeg4_prot_init();
1079 if (ret < 0) {
1080 if (mm_blk_handle) {
1081 decoder_bmmu_box_free(mm_blk_handle);
1082 mm_blk_handle = NULL;
1083 }
1084 return ret;
1085 }
1086 amvdec_enable();
1087 fr_hint_status = VDEC_NO_NEED_HINT;
1088#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
1089 vf_provider_init(&vmpeg_vf_prov, PROVIDER_NAME, &vmpeg_vf_provider,
1090 NULL);
1091 vf_reg_provider(&vmpeg_vf_prov);
1092 vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
1093#else
1094 vf_provider_init(&vmpeg_vf_prov, PROVIDER_NAME, &vmpeg_vf_provider,
1095 NULL);
1096 vf_reg_provider(&vmpeg_vf_prov);
1097#endif
1098 if (vmpeg4_amstream_dec_info.rate != 0) {
1099 if (!is_reset) {
1100 vf_notify_receiver(PROVIDER_NAME,
1101 VFRAME_EVENT_PROVIDER_FR_HINT,
1102 (void *)
1103 ((unsigned long)
1104 vmpeg4_amstream_dec_info.rate));
1105 fr_hint_status = VDEC_HINTED;
1106 }
1107 } else
1108 fr_hint_status = VDEC_NEED_HINT;
1109
1110 stat |= STAT_VF_HOOK;
1111
1112 recycle_timer.data = (ulong)&recycle_timer;
1113 recycle_timer.function = vmpeg_put_timer_func;
1114 recycle_timer.expires = jiffies + PUT_INTERVAL;
1115
1116 add_timer(&recycle_timer);
1117
1118 stat |= STAT_TIMER_ARM;
1119
1120 amvdec_start();
1121
1122 stat |= STAT_VDEC_RUN;
1123
1124 return 0;
1125}
1126
1127static int amvdec_mpeg4_probe(struct platform_device *pdev)
1128{
1129 struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
1130
1131 if (pdata == NULL) {
1132 amlog_level(LOG_LEVEL_ERROR,
1133 "amvdec_mpeg4 memory resource undefined.\n");
1134 return -EFAULT;
1135 }
1136
1137 if (pdata->sys_info) {
1138 vmpeg4_amstream_dec_info = *pdata->sys_info;
1139 if ((vmpeg4_amstream_dec_info.height != 0) &&
1140 (vmpeg4_amstream_dec_info.width >
1141 (MAX_MPEG4_SUPPORT_SIZE/vmpeg4_amstream_dec_info.height))) {
1142 pr_info("amvdec_mpeg4: oversize, unsupport: %d*%d\n",
1143 vmpeg4_amstream_dec_info.width,
1144 vmpeg4_amstream_dec_info.height);
1145 return -EFAULT;
1146 }
1147 }
1148 pdata->dec_status = vmpeg4_dec_status;
1149 pdata->set_isreset = vmpeg4_set_isreset;
1150 is_reset = 0;
1151
1152 INIT_WORK(&reset_work, reset_do_work);
1153 INIT_WORK(&notify_work, vmpeg4_notify_work);
1154 INIT_WORK(&set_clk_work, vmpeg4_set_clk);
1155
1156 vmpeg4_vdec_info_init();
1157
1158 if (vmpeg4_init() < 0) {
1159 amlog_level(LOG_LEVEL_ERROR, "amvdec_mpeg4 init failed.\n");
1160 kfree(gvs);
1161 gvs = NULL;
1162 pdata->dec_status = NULL;
1163 return -ENODEV;
1164 }
1165
1166 return 0;
1167}
1168
1169static int amvdec_mpeg4_remove(struct platform_device *pdev)
1170{
1171 if (stat & STAT_VDEC_RUN) {
1172 amvdec_stop();
1173 stat &= ~STAT_VDEC_RUN;
1174 }
1175
1176 if (stat & STAT_ISR_REG) {
1177 vdec_free_irq(VDEC_IRQ_1, (void *)vmpeg4_dec_id);
1178 stat &= ~STAT_ISR_REG;
1179 }
1180
1181 if (stat & STAT_TIMER_ARM) {
1182 del_timer_sync(&recycle_timer);
1183 stat &= ~STAT_TIMER_ARM;
1184 }
1185
1186 if (stat & STAT_VF_HOOK) {
1187 if (fr_hint_status == VDEC_HINTED)
1188 vf_notify_receiver(PROVIDER_NAME,
1189 VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
1190 fr_hint_status = VDEC_NO_NEED_HINT;
1191
1192 vf_unreg_provider(&vmpeg_vf_prov);
1193 stat &= ~STAT_VF_HOOK;
1194 }
1195
1196 cancel_work_sync(&reset_work);
1197 cancel_work_sync(&notify_work);
1198 cancel_work_sync(&set_clk_work);
1199
1200 amvdec_disable();
1201 if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TM2)
1202 vdec_reset_core(NULL);
1203 if (mm_blk_handle) {
1204 decoder_bmmu_box_free(mm_blk_handle);
1205 mm_blk_handle = NULL;
1206 }
1207
1208 amlog_mask(LOG_MASK_PTS,
1209 "pts hit %d, pts missed %d, i hit %d, missed %d\n", pts_hit,
1210 pts_missed, pts_i_hit, pts_i_missed);
1211 amlog_mask(LOG_MASK_PTS, "total frame %d, rate %d\n", total_frame,
1212 vmpeg4_amstream_dec_info.rate);
1213 kfree(gvs);
1214 gvs = NULL;
1215
1216 return 0;
1217}
1218
1219/****************************************/
1220#ifdef CONFIG_PM
1221static int mpeg4_suspend(struct device *dev)
1222{
1223 amvdec_suspend(to_platform_device(dev), dev->power.power_state);
1224 return 0;
1225}
1226
1227static int mpeg4_resume(struct device *dev)
1228{
1229 amvdec_resume(to_platform_device(dev));
1230 return 0;
1231}
1232
1233static const struct dev_pm_ops mpeg4_pm_ops = {
1234 SET_SYSTEM_SLEEP_PM_OPS(mpeg4_suspend, mpeg4_resume)
1235};
1236#endif
1237
1238static struct platform_driver amvdec_mpeg4_driver = {
1239 .probe = amvdec_mpeg4_probe,
1240 .remove = amvdec_mpeg4_remove,
1241 .driver = {
1242 .name = DRIVER_NAME,
1243#ifdef CONFIG_PM
1244 .pm = &mpeg4_pm_ops,
1245#endif
1246 }
1247};
1248
1249static struct codec_profile_t amvdec_mpeg4_profile = {
1250 .name = "mpeg4",
1251 .profile = ""
1252};
1253static struct mconfig mpeg4_configs[] = {
1254 MC_PU32("stat", &stat),
1255};
1256static struct mconfig_node mpeg4_node;
1257
1258static int __init amvdec_mpeg4_driver_init_module(void)
1259{
1260 amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg4 module init\n");
1261
1262 if (platform_driver_register(&amvdec_mpeg4_driver)) {
1263 amlog_level(LOG_LEVEL_ERROR,
1264 "failed to register amvdec_mpeg4 driver\n");
1265 return -ENODEV;
1266 }
1267 vcodec_profile_register(&amvdec_mpeg4_profile);
1268 INIT_REG_NODE_CONFIGS("media.decoder", &mpeg4_node,
1269 "mpeg4", mpeg4_configs, CONFIG_FOR_R);
1270 return 0;
1271}
1272
1273static void __exit amvdec_mpeg4_driver_remove_module(void)
1274{
1275 amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg4 module remove.\n");
1276
1277 platform_driver_unregister(&amvdec_mpeg4_driver);
1278}
1279
1280/****************************************/
1281module_init(amvdec_mpeg4_driver_init_module);
1282module_exit(amvdec_mpeg4_driver_remove_module);
1283
1284MODULE_DESCRIPTION("AMLOGIC MPEG4 Video Decoder Driver");
1285MODULE_LICENSE("GPL");
1286MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
1287