2 * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved.
6 * The code contained herein is licensed under the GNU General Public
7 * License. You may obtain a copy of the GNU General Public License
8 * Version 2 or later at the following locations:
10 * http://www.opensource.org/licenses/gpl-license.html
11 * http://www.gnu.org/copyleft/gpl.html
17 * @brief This file contains the IPUv3 driver device interface and fops functions.
21 #include <linux/clk.h>
22 #include <linux/cpumask.h>
23 #include <linux/delay.h>
24 #include <linux/dma-mapping.h>
25 #include <linux/err.h>
26 #include <linux/init.h>
28 #include <linux/ipu-v3.h>
29 #include <linux/kthread.h>
30 #include <linux/module.h>
31 #include <linux/platform_device.h>
32 #include <linux/poll.h>
33 #include <linux/sched.h>
34 #include <linux/sched/rt.h>
35 #include <linux/slab.h>
36 #include <linux/spinlock.h>
37 #include <linux/time.h>
38 #include <linux/types.h>
39 #include <linux/vmalloc.h>
40 #include <linux/wait.h>
42 #include <asm/cacheflush.h>
43 #include <asm/outercache.h>
45 #include "ipu_param_mem.h"
49 #define CHECK_RETCODE(cont, str, err, label, ret) \
52 dev_err(t->dev, "ERR:[0x%p]-no:0x%x "#str" ret:%d," \
53 "line:%d\n", t, t->task_no, ret, __LINE__);\
54 if (ret != -EACCES) { \
61 #define CHECK_RETCODE_CONT(cont, str, err, ret) \
64 dev_err(t->dev, "ERR:[0x%p]-no:0x%x"#str" ret:%d," \
65 "line:%d\n", t, t->task_no, ret, __LINE__);\
66 if (ret != -EACCES) { \
67 if (t->state == STATE_OK) \
75 #define CHECK_PERF(ts) \
80 #define DECLARE_PERF_VAR \
81 struct timespec ts_queue; \
82 struct timespec ts_dotask; \
83 struct timespec ts_waitirq; \
84 struct timespec ts_sche; \
85 struct timespec ts_rel; \
86 struct timespec ts_frame
88 #define PRINT_TASK_STATISTICS \
90 ts_queue = timespec_sub(tsk->ts_dotask, tsk->ts_queue); \
91 ts_dotask = timespec_sub(tsk->ts_waitirq, tsk->ts_dotask); \
92 ts_waitirq = timespec_sub(tsk->ts_inirq, tsk->ts_waitirq); \
93 ts_sche = timespec_sub(tsk->ts_wakeup, tsk->ts_inirq); \
94 ts_rel = timespec_sub(tsk->ts_rel, tsk->ts_wakeup); \
95 ts_frame = timespec_sub(tsk->ts_rel, tsk->ts_queue); \
96 dev_dbg(tsk->dev, "[0x%p] no-0x%x, ts_q:%ldus, ts_do:%ldus," \
97 "ts_waitirq:%ldus,ts_sche:%ldus, ts_rel:%ldus," \
98 "ts_frame: %ldus\n", tsk, tsk->task_no, \
99 ts_queue.tv_nsec / NSEC_PER_USEC + ts_queue.tv_sec * USEC_PER_SEC,\
100 ts_dotask.tv_nsec / NSEC_PER_USEC + ts_dotask.tv_sec * USEC_PER_SEC,\
101 ts_waitirq.tv_nsec / NSEC_PER_USEC + ts_waitirq.tv_sec * USEC_PER_SEC,\
102 ts_sche.tv_nsec / NSEC_PER_USEC + ts_sche.tv_sec * USEC_PER_SEC,\
103 ts_rel.tv_nsec / NSEC_PER_USEC + ts_rel.tv_sec * USEC_PER_SEC,\
104 ts_frame.tv_nsec / NSEC_PER_USEC + ts_frame.tv_sec * USEC_PER_SEC); \
105 if ((ts_frame.tv_nsec/NSEC_PER_USEC + ts_frame.tv_sec*USEC_PER_SEC) > \
107 dev_dbg(tsk->dev, "ts_frame larger than 80ms [0x%p] no-0x%x.\n"\
108 , tsk, tsk->task_no); \
111 #define CHECK_PERF(ts)
112 #define DECLARE_PERF_VAR
113 #define PRINT_TASK_STATISTICS
116 #define IPU_PP_CH_VF (IPU_TASK_ID_VF - 1)
117 #define IPU_PP_CH_PP (IPU_TASK_ID_PP - 1)
118 #define MAX_PP_CH (IPU_TASK_ID_MAX - 1)
119 #define VDOA_DEF_TIMEOUT_MS (HZ/2)
121 /* Strucutures and variables for exporting MXC IPU as device*/
134 STATE_ENABLE_CHAN_FAIL,
135 STATE_DISABLE_CHAN_FAIL,
137 STATE_INIT_CHAN_FAIL,
138 STATE_LINK_CHAN_FAIL,
139 STATE_UNLINK_CHAN_FAIL,
140 STATE_INIT_CHAN_BUF_FAIL,
141 STATE_INIT_CHAN_BAND_FAIL,
143 STATE_VDOA_IRQ_TIMEOUT,
145 STATE_VDOA_TASK_FAIL,
149 INPUT_CHAN_VDI_P = 1,
154 struct ipu_state_msg {
159 {STATE_QUEUE, "split queue"},
160 {STATE_IN_PROGRESS, "split in progress"},
161 {STATE_ERR, "error"},
162 {STATE_TIMEOUT, "split task timeout"},
163 {STATE_RES_TIMEOUT, "wait resource timeout"},
164 {STATE_NO_IPU, "no ipu found"},
165 {STATE_NO_IRQ, "no irq found for task"},
166 {STATE_IPU_BUSY, "ipu busy"},
167 {STATE_IRQ_FAIL, "request irq failed"},
168 {STATE_IRQ_TIMEOUT, "wait for irq timeout"},
169 {STATE_ENABLE_CHAN_FAIL, "ipu enable channel fail"},
170 {STATE_DISABLE_CHAN_FAIL, "ipu disable channel fail"},
171 {STATE_SEL_BUF_FAIL, "ipu select buf fail"},
172 {STATE_INIT_CHAN_FAIL, "ipu init channel fail"},
173 {STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
174 {STATE_UNLINK_CHAN_FAIL, "ipu unlink channel fail"},
175 {STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
176 {STATE_INIT_CHAN_BAND_FAIL, "ipu init channel band mode fail"},
177 {STATE_SYS_NO_MEM, "sys no mem: -ENOMEM"},
178 {STATE_VDOA_IRQ_TIMEOUT, "wait for vdoa irq timeout"},
179 {STATE_VDOA_IRQ_FAIL, "vdoa irq fail"},
180 {STATE_VDOA_TASK_FAIL, "vdoa task fail"},
183 struct stripe_setting {
188 u32 outh_resize_ratio;
189 u32 outv_resize_ratio;
203 #define NULL_MODE 0x0
207 #define IPU_PREPROCESS_MODE_MASK (IC_MODE | ROT_MODE | VDI_MODE)
208 /* VDOA_MODE means this task use vdoa, and VDOA has two modes:
209 * BAND MODE and non-BAND MODE. Non-band mode will do transfer data
210 * to memory. BAND mode needs hareware sync with IPU, it is used default
211 * if connected to VDIC.
213 #define VDOA_MODE 0x8
214 #define VDOA_BAND_MODE 0x10
221 #define VDOA_ONLY 0x20
226 #define LEFT_STRIPE 0x1
227 #define RIGHT_STRIPE 0x2
228 #define UP_STRIPE 0x4
229 #define DOWN_STRIPE 0x8
230 #define SPLIT_MASK 0xF
233 ipu_channel_t ic_chan;
234 ipu_channel_t rot_chan;
235 ipu_channel_t vdi_ic_p_chan;
236 ipu_channel_t vdi_ic_n_chan;
262 struct stripe_setting sp_setting;
265 struct ipu_split_task {
266 struct ipu_task task;
267 struct ipu_task_entry *parent_task;
268 struct ipu_task_entry *child_task;
272 struct ipu_task_entry {
273 struct ipu_input input;
274 struct ipu_output output;
277 struct ipu_overlay overlay;
278 #define DEF_TIMEOUT_MS 1000
279 #define DEF_DELAY_MS 20
287 struct mutex split_lock;
288 wait_queue_head_t split_waitq;
290 struct list_head node;
291 struct list_head split_list;
295 wait_queue_head_t task_waitq;
296 struct completion irq_comp;
297 struct kref refcount;
304 struct ipu_task_entry *parent;
311 vdoa_handle_t vdoa_handle;
312 struct vdoa_output_mem {
319 struct timespec ts_queue;
320 struct timespec ts_dotask;
321 struct timespec ts_waitirq;
322 struct timespec ts_inirq;
323 struct timespec ts_wakeup;
324 struct timespec ts_rel;
328 struct ipu_channel_tabel {
330 u8 used[MXC_IPU_MAX_NUM][MAX_PP_CH];
334 struct ipu_thread_data {
340 struct ipu_alloc_list {
341 struct list_head list;
348 static LIST_HEAD(ipu_alloc_list);
349 static DEFINE_MUTEX(ipu_alloc_lock);
350 static struct ipu_channel_tabel ipu_ch_tbl;
351 static LIST_HEAD(ipu_task_list);
352 static DEFINE_SPINLOCK(ipu_task_list_lock);
353 static DECLARE_WAIT_QUEUE_HEAD(thread_waitq);
354 static DECLARE_WAIT_QUEUE_HEAD(res_waitq);
355 static atomic_t req_cnt;
356 static atomic_t file_index = ATOMIC_INIT(1);
358 static int max_ipu_no;
359 static int thread_id;
360 static atomic_t frame_no;
361 static struct class *ipu_class;
362 static struct device *ipu_dev;
364 module_param(debug, int, 0600);
366 static struct timespec ts_frame_max;
367 static u32 ts_frame_avg;
368 static atomic_t frame_cnt;
371 static bool deinterlace_3_field(struct ipu_task_entry *t)
373 return ((t->set.mode & VDI_MODE) &&
374 (t->input.deinterlace.motion != HIGH_MOTION));
377 static u32 tiled_filed_size(struct ipu_task_entry *t)
381 /* note: page_align is required by VPU hw ouput buffer */
382 field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2);
386 static bool only_ic(u8 mode)
388 mode = mode & IPU_PREPROCESS_MODE_MASK;
389 return ((mode == IC_MODE) || (mode == VDI_MODE));
392 static bool only_rot(u8 mode)
394 mode = mode & IPU_PREPROCESS_MODE_MASK;
395 return (mode == ROT_MODE);
398 static bool ic_and_rot(u8 mode)
400 mode = mode & IPU_PREPROCESS_MODE_MASK;
401 return ((mode == (IC_MODE | ROT_MODE)) ||
402 (mode == (VDI_MODE | ROT_MODE)));
405 static bool need_split(struct ipu_task_entry *t)
407 return ((t->set.split_mode != NO_SPLIT) || (t->task_no & SPLIT_MASK));
410 unsigned int fmt_to_bpp(unsigned int pixelformat)
414 switch (pixelformat) {
415 case IPU_PIX_FMT_RGB565:
417 case IPU_PIX_FMT_YUYV:
418 case IPU_PIX_FMT_UYVY:
419 /*non-interleaved 422*/
420 case IPU_PIX_FMT_YUV422P:
421 case IPU_PIX_FMT_YVU422P:
424 case IPU_PIX_FMT_BGR24:
425 case IPU_PIX_FMT_RGB24:
426 case IPU_PIX_FMT_YUV444:
427 case IPU_PIX_FMT_YUV444P:
430 case IPU_PIX_FMT_BGR32:
431 case IPU_PIX_FMT_BGRA32:
432 case IPU_PIX_FMT_RGB32:
433 case IPU_PIX_FMT_RGBA32:
434 case IPU_PIX_FMT_ABGR32:
437 /*non-interleaved 420*/
438 case IPU_PIX_FMT_YUV420P:
439 case IPU_PIX_FMT_YVU420P:
440 case IPU_PIX_FMT_YUV420P2:
441 case IPU_PIX_FMT_NV12:
450 EXPORT_SYMBOL_GPL(fmt_to_bpp);
452 cs_t colorspaceofpixel(int fmt)
455 case IPU_PIX_FMT_RGB565:
456 case IPU_PIX_FMT_BGR24:
457 case IPU_PIX_FMT_RGB24:
458 case IPU_PIX_FMT_BGRA32:
459 case IPU_PIX_FMT_BGR32:
460 case IPU_PIX_FMT_RGBA32:
461 case IPU_PIX_FMT_RGB32:
462 case IPU_PIX_FMT_ABGR32:
465 case IPU_PIX_FMT_UYVY:
466 case IPU_PIX_FMT_YUYV:
467 case IPU_PIX_FMT_YUV420P2:
468 case IPU_PIX_FMT_YUV420P:
469 case IPU_PIX_FMT_YVU420P:
470 case IPU_PIX_FMT_YVU422P:
471 case IPU_PIX_FMT_YUV422P:
472 case IPU_PIX_FMT_YUV444:
473 case IPU_PIX_FMT_YUV444P:
474 case IPU_PIX_FMT_NV12:
475 case IPU_PIX_FMT_TILED_NV12:
476 case IPU_PIX_FMT_TILED_NV12F:
483 EXPORT_SYMBOL_GPL(colorspaceofpixel);
485 int need_csc(int ifmt, int ofmt)
489 ics = colorspaceofpixel(ifmt);
490 ocs = colorspaceofpixel(ofmt);
492 if ((ics == NULL_CS) || (ocs == NULL_CS))
499 EXPORT_SYMBOL_GPL(need_csc);
501 static int soc_max_in_width(u32 is_vdoa)
503 return is_vdoa ? 8192 : 4096;
506 static int soc_max_vdi_in_width(void)
508 return IPU_MAX_VDI_IN_WIDTH;
510 static int soc_max_in_height(void)
515 static int soc_max_out_width(void)
517 /* mx51/mx53/mx6q is 1024*/
521 static int soc_max_out_height(void)
523 /* mx51/mx53/mx6q is 1024*/
527 static void dump_task_info(struct ipu_task_entry *t)
531 dev_dbg(t->dev, "[0x%p]input:\n", (void *)t);
532 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format);
533 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width);
534 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height);
535 dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w);
536 dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h);
537 dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
538 (void *)t, t->input.crop.pos.x);
539 dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
540 (void *)t, t->input.crop.pos.y);
541 dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t);
542 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr);
543 dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off);
544 dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff);
545 dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff);
546 dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride);
547 if (t->input.deinterlace.enable) {
548 dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t);
549 if (t->input.deinterlace.motion != HIGH_MOTION) {
550 dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t);
551 dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n",
552 (void *)t, t->input.paddr_n);
554 dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t);
557 dev_dbg(t->dev, "[0x%p]output:\n", (void *)t);
558 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format);
559 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width);
560 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height);
561 dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w);
562 dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h);
563 dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
564 (void *)t, t->output.crop.pos.x);
565 dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
566 (void *)t, t->output.crop.pos.y);
567 dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate);
568 dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t);
569 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr);
570 dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off);
571 dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff);
572 dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff);
573 dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride);
576 dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t);
577 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n",
578 (void *)t, t->overlay.format);
579 dev_dbg(t->dev, "[0x%p]\twidth = %d\n",
580 (void *)t, t->overlay.width);
581 dev_dbg(t->dev, "[0x%p]\theight = %d\n",
582 (void *)t, t->overlay.height);
583 dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n",
584 (void *)t, t->overlay.crop.w);
585 dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n",
586 (void *)t, t->overlay.crop.h);
587 dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
588 (void *)t, t->overlay.crop.pos.x);
589 dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
590 (void *)t, t->overlay.crop.pos.y);
591 dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t);
592 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
593 (void *)t, t->overlay.paddr);
594 dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n",
595 (void *)t, t->set.ov_off);
596 dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n",
597 (void *)t, t->set.ov_uoff);
598 dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n",
599 (void *)t, t->set.ov_voff);
600 dev_dbg(t->dev, "[0x%p]\tovstride = %d\n",
601 (void *)t, t->set.ovstride);
602 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
603 dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n",
605 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
606 (void *)t, t->overlay.alpha.loc_alp_paddr);
607 dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n",
608 (void *)t, t->set.ov_alpha_off);
609 dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n",
610 (void *)t, t->set.ov_alpha_stride);
612 dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n",
613 (void *)t, t->overlay.alpha.gvalue);
614 if (t->overlay.colorkey.enable)
615 dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n",
616 (void *)t, t->overlay.colorkey.value);
619 dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id);
620 dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n",
621 (void *)t, t->set.mode);
622 dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE);
623 dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE);
624 dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE);
625 dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no);
628 static void dump_check_err(struct device *dev, int err)
631 case IPU_CHECK_ERR_INPUT_CROP:
632 dev_err(dev, "input crop setting error\n");
634 case IPU_CHECK_ERR_OUTPUT_CROP:
635 dev_err(dev, "output crop setting error\n");
637 case IPU_CHECK_ERR_OVERLAY_CROP:
638 dev_err(dev, "overlay crop setting error\n");
640 case IPU_CHECK_ERR_INPUT_OVER_LIMIT:
641 dev_err(dev, "input over limitation\n");
643 case IPU_CHECK_ERR_OVERLAY_WITH_VDI:
644 dev_err(dev, "do not support overlay with deinterlace\n");
646 case IPU_CHECK_ERR_OV_OUT_NO_FIT:
648 "width/height of overlay and ic output should be same\n");
650 case IPU_CHECK_ERR_PROC_NO_NEED:
651 dev_err(dev, "no ipu processing need\n");
653 case IPU_CHECK_ERR_SPLIT_INPUTW_OVER:
654 dev_err(dev, "split mode input width overflow\n");
656 case IPU_CHECK_ERR_SPLIT_INPUTH_OVER:
657 dev_err(dev, "split mode input height overflow\n");
659 case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER:
660 dev_err(dev, "split mode output width overflow\n");
662 case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER:
663 dev_err(dev, "split mode output height overflow\n");
665 case IPU_CHECK_ERR_SPLIT_WITH_ROT:
666 dev_err(dev, "not support split mode with rotation\n");
668 case IPU_CHECK_ERR_W_DOWNSIZE_OVER:
669 dev_err(dev, "horizontal downsizing ratio overflow\n");
671 case IPU_CHECK_ERR_H_DOWNSIZE_OVER:
672 dev_err(dev, "vertical downsizing ratio overflow\n");
679 static void dump_check_warn(struct device *dev, int warn)
681 if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
682 dev_warn(dev, "input u/v offset not 8 align\n");
683 if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
684 dev_warn(dev, "output u/v offset not 8 align\n");
685 if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
686 dev_warn(dev, "overlay u/v offset not 8 align\n");
689 static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
691 if ((width == 0) || (height == 0)) {
692 pr_err("Invalid param: width=%d, height=%d\n", width, height);
696 if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
697 (IPU_PIX_FMT_TILED_NV12F == fmt)) {
698 if (crop->w || crop->h) {
699 if (((crop->w + crop->pos.x) > width)
700 || ((crop->h + crop->pos.y) > height)
701 || (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
702 || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
703 || (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
704 || (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
706 pr_err("set_crop error MB align.\n");
714 if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
715 || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
716 pr_err("set_crop error w/h MB align.\n");
721 if (crop->w || crop->h) {
722 if (((crop->w + crop->pos.x) > width)
723 || ((crop->h + crop->pos.y) > height))
731 crop->w -= crop->w%8;
732 crop->h -= crop->h%8;
735 if ((crop->w == 0) || (crop->h == 0)) {
736 pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
744 static void update_offset(unsigned int fmt,
745 unsigned int width, unsigned int height,
746 unsigned int pos_x, unsigned int pos_y,
747 int *off, int *uoff, int *voff, int *stride)
749 /* NOTE: u v offset should based on start point of off*/
751 case IPU_PIX_FMT_YUV420P2:
752 case IPU_PIX_FMT_YUV420P:
753 *off = pos_y * width + pos_x;
754 *uoff = (width * (height - pos_y) - pos_x)
755 + (width/2) * (pos_y/2) + pos_x/2;
756 /* In case height is odd, round up to even */
757 *voff = *uoff + (width/2) * ((height+1)/2);
759 case IPU_PIX_FMT_YVU420P:
760 *off = pos_y * width + pos_x;
761 *voff = (width * (height - pos_y) - pos_x)
762 + (width/2) * (pos_y/2) + pos_x/2;
763 /* In case height is odd, round up to even */
764 *uoff = *voff + (width/2) * ((height+1)/2);
766 case IPU_PIX_FMT_YVU422P:
767 *off = pos_y * width + pos_x;
768 *voff = (width * (height - pos_y) - pos_x)
769 + (width/2) * pos_y + pos_x/2;
770 *uoff = *voff + (width/2) * height;
772 case IPU_PIX_FMT_YUV422P:
773 *off = pos_y * width + pos_x;
774 *uoff = (width * (height - pos_y) - pos_x)
775 + (width/2) * pos_y + pos_x/2;
776 *voff = *uoff + (width/2) * height;
778 case IPU_PIX_FMT_YUV444P:
779 *off = pos_y * width + pos_x;
780 *uoff = width * height;
781 *voff = width * height * 2;
783 case IPU_PIX_FMT_NV12:
784 *off = pos_y * width + pos_x;
785 *uoff = (width * (height - pos_y) - pos_x)
786 + width * (pos_y/2) + pos_x;
788 case IPU_PIX_FMT_TILED_NV12:
790 * tiled format, progressive:
791 * assuming that line is aligned with MB height (aligned to 16)
792 * offset = line * stride + (pixel / MB_width) * pixels_in_MB
793 * = line * stride + (pixel / 16) * 256
794 * = line * stride + pixel * 16
796 *off = pos_y * width + (pos_x << 4);
797 *uoff = ALIGN(width * height, SZ_4K) + (*off >> 1) - *off;
799 case IPU_PIX_FMT_TILED_NV12F:
801 * tiled format, interlaced:
802 * same as above, only number of pixels in MB is 128,
805 *off = (pos_y >> 1) * width + (pos_x << 3);
806 *uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1) - *off;
809 *off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
812 *stride = width * bytes_per_pixel(fmt);
815 static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
817 struct stripe_param left_stripe;
818 struct stripe_param right_stripe;
819 struct stripe_param up_stripe;
820 struct stripe_param down_stripe;
825 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
826 return IPU_CHECK_ERR_SPLIT_WITH_ROT;
828 iw = t->input.crop.w;
829 ih = t->input.crop.h;
831 ow = t->output.crop.w;
832 oh = t->output.crop.h;
834 memset(&left_stripe, 0, sizeof(left_stripe));
835 memset(&right_stripe, 0, sizeof(right_stripe));
836 memset(&up_stripe, 0, sizeof(up_stripe));
837 memset(&down_stripe, 0, sizeof(down_stripe));
839 if (t->set.split_mode & RL_SPLIT) {
841 * We do want equal strips: initialize stripes in case
842 * calc_stripes returns before actually doing the calculation
844 left_stripe.input_width = iw / 2;
845 left_stripe.output_width = ow / 2;
846 right_stripe.input_column = iw / 2;
847 right_stripe.output_column = ow / 2;
850 max_width = soc_max_vdi_in_width();
852 max_width = soc_max_out_width();
853 ret = ipu_calc_stripes_sizes(iw,
856 (((unsigned long long)1) << 32), /* 32bit for fractional*/
857 1, /* equal stripes */
863 dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
865 t->set.sp_setting.iw = left_stripe.input_width;
866 t->set.sp_setting.ow = left_stripe.output_width;
867 t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
868 t->set.sp_setting.i_left_pos = left_stripe.input_column;
869 t->set.sp_setting.o_left_pos = left_stripe.output_column;
870 t->set.sp_setting.i_right_pos = right_stripe.input_column;
871 t->set.sp_setting.o_right_pos = right_stripe.output_column;
873 t->set.sp_setting.iw = iw;
874 t->set.sp_setting.ow = ow;
875 t->set.sp_setting.outh_resize_ratio = 0;
876 t->set.sp_setting.i_left_pos = 0;
877 t->set.sp_setting.o_left_pos = 0;
878 t->set.sp_setting.i_right_pos = 0;
879 t->set.sp_setting.o_right_pos = 0;
881 if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > iw)
882 return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
883 if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
884 || (t->set.sp_setting.ow > soc_max_out_width()))
885 return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
887 if (t->set.split_mode & UD_SPLIT) {
889 * We do want equal strips: initialize stripes in case
890 * calc_stripes returns before actually doing the calculation
892 up_stripe.input_width = ih / 2;
893 up_stripe.output_width = oh / 2;
894 down_stripe.input_column = ih / 2;
895 down_stripe.output_column = oh / 2;
896 ret = ipu_calc_stripes_sizes(ih,
898 soc_max_out_height(),
899 (((unsigned long long)1) << 32), /* 32bit for fractional*/
900 1, /* equal stripes */
906 dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
908 t->set.sp_setting.ih = up_stripe.input_width;
909 t->set.sp_setting.oh = up_stripe.output_width;
910 t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
911 t->set.sp_setting.i_top_pos = up_stripe.input_column;
912 t->set.sp_setting.o_top_pos = up_stripe.output_column;
913 t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
914 t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
916 t->set.sp_setting.ih = ih;
917 t->set.sp_setting.oh = oh;
918 t->set.sp_setting.outv_resize_ratio = 0;
919 t->set.sp_setting.i_top_pos = 0;
920 t->set.sp_setting.o_top_pos = 0;
921 t->set.sp_setting.i_bottom_pos = 0;
922 t->set.sp_setting.o_bottom_pos = 0;
924 if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > ih)
925 return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
926 if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
927 || (t->set.sp_setting.oh > soc_max_out_height()))
928 return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
933 static int check_task(struct ipu_task_entry *t)
936 int ret = IPU_CHECK_OK;
938 bool vdi_split = false;
940 if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
941 (IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
942 (IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
943 (IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
944 ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
945 !t->input.deinterlace.enable)) {
946 ret = IPU_CHECK_ERR_NOT_SUPPORT;
951 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
954 ret = IPU_CHECK_ERR_INPUT_CROP;
957 update_offset(t->input.format, t->input.width, t->input.height,
958 t->input.crop.pos.x, t->input.crop.pos.y,
959 &t->set.i_off, &t->set.i_uoff,
960 &t->set.i_voff, &t->set.istride);
963 ret = set_crop(&t->output.crop, t->output.width, t->output.height,
966 ret = IPU_CHECK_ERR_OUTPUT_CROP;
969 update_offset(t->output.format,
970 t->output.width, t->output.height,
971 t->output.crop.pos.x, t->output.crop.pos.y,
972 &t->set.o_off, &t->set.o_uoff,
973 &t->set.o_voff, &t->set.ostride);
975 if (t->output.crop.w * 8 <= t->input.crop.w) {
976 ret = IPU_CHECK_ERR_W_DOWNSIZE_OVER;
980 if (t->output.crop.h * 8 <= t->input.crop.h) {
981 ret = IPU_CHECK_ERR_H_DOWNSIZE_OVER;
985 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
986 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
987 if ((t->input.crop.w > soc_max_in_width(1)) ||
988 (t->input.crop.h > soc_max_in_height())) {
989 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
992 /* output fmt: NV12 and YUYV, now don't support resize */
993 if (((IPU_PIX_FMT_NV12 != t->output.format) &&
994 (IPU_PIX_FMT_YUYV != t->output.format)) ||
995 (t->input.crop.w != t->output.crop.w) ||
996 (t->input.crop.h != t->output.crop.h)) {
997 ret = IPU_CHECK_ERR_NOT_SUPPORT;
1002 /* check overlay if there is */
1003 if (t->overlay_en) {
1004 if (t->input.deinterlace.enable) {
1005 ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
1009 ret = set_crop(&t->overlay.crop, t->overlay.width,
1010 t->overlay.height, t->overlay.format);
1012 ret = IPU_CHECK_ERR_OVERLAY_CROP;
1015 int ow = t->output.crop.w;
1016 int oh = t->output.crop.h;
1018 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1019 ow = t->output.crop.h;
1020 oh = t->output.crop.w;
1022 if ((t->overlay.crop.w != ow) || (t->overlay.crop.h != oh)) {
1023 ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
1027 update_offset(t->overlay.format,
1028 t->overlay.width, t->overlay.height,
1029 t->overlay.crop.pos.x, t->overlay.crop.pos.y,
1030 &t->set.ov_off, &t->set.ov_uoff,
1031 &t->set.ov_voff, &t->set.ovstride);
1032 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
1033 t->set.ov_alpha_stride = t->overlay.width;
1034 t->set.ov_alpha_off = t->overlay.crop.pos.y *
1035 t->overlay.width + t->overlay.crop.pos.x;
1040 /* input overflow? */
1041 if (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1042 (IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
1043 if ((t->input.crop.w > soc_max_in_width(0)) ||
1044 (t->input.crop.h > soc_max_in_height())) {
1045 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
1050 /* check task mode */
1051 t->set.mode = NULL_MODE;
1052 t->set.split_mode = NO_SPLIT;
1054 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1056 tmp = t->output.crop.w;
1057 t->output.crop.w = t->output.crop.h;
1058 t->output.crop.h = tmp;
1061 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
1062 t->set.mode |= ROT_MODE;
1064 /*need resize or CSC?*/
1065 if ((t->input.crop.w != t->output.crop.w) ||
1066 (t->input.crop.h != t->output.crop.h) ||
1067 need_csc(t->input.format, t->output.format))
1068 t->set.mode |= IC_MODE;
1071 if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
1072 t->set.mode |= IC_MODE;
1074 /*need IDMAC do format(same color space)?*/
1075 if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
1076 t->set.mode |= IC_MODE;
1080 t->set.mode |= IC_MODE;
1083 if (t->input.deinterlace.enable) {
1084 t->set.mode &= ~IC_MODE;
1085 t->set.mode |= VDI_MODE;
1087 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1088 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1089 if (t->set.mode & ROT_MODE) {
1090 ret = IPU_CHECK_ERR_NOT_SUPPORT;
1093 t->set.mode |= VDOA_MODE;
1094 if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
1095 t->set.mode |= VDOA_BAND_MODE;
1096 t->set.mode &= ~IC_MODE;
1099 if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
1100 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
1101 if (t->output.crop.w > soc_max_out_width())
1102 t->set.split_mode |= RL_SPLIT;
1103 if (t->output.crop.h > soc_max_out_height())
1104 t->set.split_mode |= UD_SPLIT;
1105 if (!t->set.split_mode && (t->set.mode & VDI_MODE) &&
1106 (t->input.crop.w > soc_max_vdi_in_width())) {
1107 t->set.split_mode |= RL_SPLIT;
1110 if (t->set.split_mode) {
1111 if ((t->set.split_mode == RL_SPLIT) ||
1112 (t->set.split_mode == UD_SPLIT))
1113 timeout = DEF_TIMEOUT_MS * 2 + DEF_DELAY_MS;
1115 timeout = DEF_TIMEOUT_MS * 4 + DEF_DELAY_MS;
1116 if (t->timeout < timeout)
1117 t->timeout = timeout;
1119 ret = update_split_setting(t, vdi_split);
1120 if (ret > IPU_CHECK_ERR_MIN)
1125 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1127 tmp = t->output.crop.w;
1128 t->output.crop.w = t->output.crop.h;
1129 t->output.crop.h = tmp;
1132 if (t->set.mode == NULL_MODE) {
1133 ret = IPU_CHECK_ERR_PROC_NO_NEED;
1137 if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
1138 ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
1139 if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
1140 ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
1141 if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
1142 ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
1147 if (ret > IPU_CHECK_ERR_MIN)
1148 dump_check_err(t->dev, ret);
1149 else if (ret != IPU_CHECK_OK)
1150 dump_check_warn(t->dev, ret);
1156 static int prepare_task(struct ipu_task_entry *t)
1160 ret = check_task(t);
1161 if (ret > IPU_CHECK_ERR_MIN)
1164 if (t->set.mode & VDI_MODE) {
1165 t->task_id = IPU_TASK_ID_VF;
1166 t->set.task = VDI_VF;
1167 if (t->set.mode & ROT_MODE)
1168 t->set.task |= ROT_VF;
1171 if (VDOA_MODE == t->set.mode) {
1172 if (t->set.task != 0) {
1173 dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
1177 t->set.task |= VDOA_ONLY;
1180 if (VDOA_BAND_MODE & t->set.mode) {
1181 /* to save band size: 1<<3 = 8 lines */
1182 t->set.band_lines = 3;
1190 static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
1194 uint32_t status_rot;
1197 status = ipu_channel_status(ipu, MEM_VDI_PRP_VF_MEM);
1198 status_vf = ipu_channel_status(ipu, MEM_PRP_VF_MEM);
1199 status_rot = ipu_channel_status(ipu, MEM_ROT_VF_MEM);
1200 return status || status_vf || status_rot;
1202 status = ipu_channel_status(ipu, MEM_PP_MEM);
1203 status_rot = ipu_channel_status(ipu, MEM_ROT_PP_MEM);
1204 return status || status_rot;
1208 static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
1211 struct ipu_soc *ipu;
1213 uint32_t found_ipu = 0;
1214 uint32_t found_vdoa = 0;
1215 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1217 mutex_lock(&tbl->lock);
1218 if (t->set.mode & VDOA_MODE) {
1219 if (NULL != t->vdoa_handle)
1222 found_vdoa = tbl->vdoa_used ? 0 : 1;
1225 vdoa_get_handle(&t->vdoa_handle);
1227 /* first get vdoa->ipu resource sequence */
1229 if (t->set.task & VDOA_ONLY)
1234 for (i = 0; i < max_ipu_no; i++) {
1235 ipu = ipu_get_soc(i);
1237 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1238 t->task_no, found_vdoa, i);
1240 used = &tbl->used[i][IPU_PP_CH_VF];
1241 if (t->set.mode & VDI_MODE) {
1247 } else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1249 t->task_id = IPU_TASK_ID_VF;
1250 if (t->set.mode & IC_MODE)
1251 t->set.task |= IC_VF;
1252 if (t->set.mode & ROT_MODE)
1253 t->set.task |= ROT_VF;
1259 dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n",
1260 t->task_no, found_vdoa, t->set.mode);
1265 for (i = 0; i < max_ipu_no; i++) {
1266 ipu = ipu_get_soc(i);
1268 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1269 t->task_no, found_vdoa, i);
1271 if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1272 used = &tbl->used[i][IPU_PP_CH_PP];
1274 t->task_id = IPU_TASK_ID_PP;
1275 if (t->set.mode & IC_MODE)
1276 t->set.task |= IC_PP;
1277 if (t->set.mode & ROT_MODE)
1278 t->set.task |= ROT_PP;
1291 if (atomic_inc_return(&t->res_get) == 2)
1293 "ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
1294 t->task_no, found_vdoa);
1298 "%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
1299 __func__, t->task_no, found_vdoa, found_ipu);
1300 mutex_unlock(&tbl->lock);
1301 if (t->set.task & VDOA_ONLY)
1303 else if (t->set.mode & VDOA_MODE)
1304 return found_vdoa && found_ipu;
1309 static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
1312 int rel_vdoa = 0, rel_ipu = 0;
1313 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1315 mutex_lock(&tbl->lock);
1316 if (tsk->set.mode & VDOA_MODE) {
1317 if (!tbl->vdoa_used && tsk->vdoa_handle)
1319 "ERR no:0x%x,vdoa not used,mode:0x%x\n",
1320 tsk->task_no, tsk->set.mode);
1321 if (tbl->vdoa_used && tsk->vdoa_handle) {
1323 vdoa_put_handle(&tsk->vdoa_handle);
1325 tsk->ipu->vdoa_en = 0;
1327 if (vdoa_only || (tsk->set.task & VDOA_ONLY))
1332 tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
1334 ret = atomic_inc_return(&tsk->res_free);
1337 "ERR no:0x%x,rel_vdoa:%d,put ipu twice\n",
1338 tsk->task_no, rel_vdoa);
1341 "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
1342 __func__, tsk->task_no, rel_vdoa, rel_ipu);
1343 mutex_unlock(&tbl->lock);
1346 static int get_vdoa_ipu_res(struct ipu_task_entry *t)
1351 found = _get_vdoa_ipu_res(t);
1355 /* blocking to get resource */
1356 ret = atomic_inc_return(&req_cnt);
1358 "wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
1359 ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
1360 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
1362 dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
1363 t, t->task_no, t->timeout - DEF_DELAY_MS);
1365 t->state = STATE_RES_TIMEOUT;
1368 if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
1370 "ERR[no-0x%x] can not get ipu!\n",
1372 ret = atomic_read(&req_cnt);
1374 ret = atomic_dec_return(&req_cnt);
1377 "ERR[no-0x%x] req_cnt:%d mismatch!\n",
1379 dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n",
1380 t->task_no, t, ret);
1389 static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
1391 struct ipu_task_entry *tsk;
1393 tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
1395 return ERR_PTR(-ENOMEM);
1396 kref_init(&tsk->refcount);
1397 tsk->state = -EINVAL;
1400 tsk->input = task->input;
1401 tsk->output = task->output;
1402 tsk->overlay_en = task->overlay_en;
1403 if (tsk->overlay_en)
1404 tsk->overlay = task->overlay;
1405 if (task->timeout > DEF_TIMEOUT_MS)
1406 tsk->timeout = task->timeout;
1408 tsk->timeout = DEF_TIMEOUT_MS;
1413 static void task_mem_free(struct kref *ref)
1415 struct ipu_task_entry *tsk =
1416 container_of(ref, struct ipu_task_entry, refcount);
1418 memset(tsk, 0, sizeof(*tsk));
1422 int create_split_child_task(struct ipu_split_task *sp_task)
1425 struct ipu_task_entry *tsk;
1427 tsk = create_task_entry(&sp_task->task);
1429 return PTR_ERR(tsk);
1431 sp_task->child_task = tsk;
1432 tsk->task_no = sp_task->task_no;
1434 ret = prepare_task(tsk);
1438 tsk->parent = sp_task->parent_task;
1439 tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
1441 list_add(&tsk->node, &tsk->parent->split_list);
1442 dev_dbg(tsk->dev, "[0x%p] sp_tsk Q list,no-0x%x\n", tsk, tsk->task_no);
1443 tsk->state = STATE_QUEUE;
1444 CHECK_PERF(&tsk->ts_queue);
1449 static inline int sp_task_check_done(struct ipu_split_task *sp_task,
1450 struct ipu_task_entry *parent, int num, int *idx)
1454 struct ipu_task_entry *tsk;
1455 struct mutex *lock = &parent->split_lock;
1459 for (i = 0; i < num; i++) {
1460 tsk = sp_task[i].child_task;
1461 if (tsk && tsk->split_done) {
1473 static int create_split_task(
1475 struct ipu_split_task *sp_task)
1477 struct ipu_task *task = &(sp_task->task);
1478 struct ipu_task_entry *t = sp_task->parent_task;
1481 sp_task->task_no |= stripe;
1483 task->input = t->input;
1484 task->output = t->output;
1485 task->overlay_en = t->overlay_en;
1486 if (task->overlay_en)
1487 task->overlay = t->overlay;
1488 task->task_id = t->task_id;
1489 if ((t->set.split_mode == RL_SPLIT) ||
1490 (t->set.split_mode == UD_SPLIT))
1491 task->timeout = t->timeout / 2;
1493 task->timeout = t->timeout / 4;
1495 task->input.crop.w = t->set.sp_setting.iw;
1496 task->input.crop.h = t->set.sp_setting.ih;
1497 if (task->overlay_en) {
1498 task->overlay.crop.w = t->set.sp_setting.ow;
1499 task->overlay.crop.h = t->set.sp_setting.oh;
1501 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1502 task->output.crop.w = t->set.sp_setting.oh;
1503 task->output.crop.h = t->set.sp_setting.ow;
1504 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos;
1505 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos;
1508 task->output.crop.w = t->set.sp_setting.ow;
1509 task->output.crop.h = t->set.sp_setting.oh;
1510 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos;
1511 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos;
1514 if (stripe & LEFT_STRIPE)
1515 task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
1516 else if (stripe & RIGHT_STRIPE)
1517 task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
1518 if (stripe & UP_STRIPE)
1519 task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
1520 else if (stripe & DOWN_STRIPE)
1521 task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
1523 if (task->overlay_en) {
1524 if (stripe & LEFT_STRIPE)
1525 task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
1526 else if (stripe & RIGHT_STRIPE)
1527 task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
1528 if (stripe & UP_STRIPE)
1529 task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
1530 else if (stripe & DOWN_STRIPE)
1531 task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1534 switch (t->output.rotate) {
1535 case IPU_ROTATE_NONE:
1536 if (stripe & LEFT_STRIPE)
1537 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1538 else if (stripe & RIGHT_STRIPE)
1539 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1540 if (stripe & UP_STRIPE)
1541 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1542 else if (stripe & DOWN_STRIPE)
1543 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1545 case IPU_ROTATE_VERT_FLIP:
1546 if (stripe & LEFT_STRIPE)
1547 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1548 else if (stripe & RIGHT_STRIPE)
1549 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1550 if (stripe & UP_STRIPE)
1551 task->output.crop.pos.y =
1552 t->output.crop.pos.y + t->output.crop.h
1553 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1554 else if (stripe & DOWN_STRIPE)
1555 task->output.crop.pos.y =
1556 t->output.crop.pos.y + t->output.crop.h
1557 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1559 case IPU_ROTATE_HORIZ_FLIP:
1560 if (stripe & LEFT_STRIPE)
1561 task->output.crop.pos.x =
1562 t->output.crop.pos.x + t->output.crop.w
1563 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1564 else if (stripe & RIGHT_STRIPE)
1565 task->output.crop.pos.x =
1566 t->output.crop.pos.x + t->output.crop.w
1567 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1568 if (stripe & UP_STRIPE)
1569 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1570 else if (stripe & DOWN_STRIPE)
1571 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1573 case IPU_ROTATE_180:
1574 if (stripe & LEFT_STRIPE)
1575 task->output.crop.pos.x =
1576 t->output.crop.pos.x + t->output.crop.w
1577 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1578 else if (stripe & RIGHT_STRIPE)
1579 task->output.crop.pos.x =
1580 t->output.crop.pos.x + t->output.crop.w
1581 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1582 if (stripe & UP_STRIPE)
1583 task->output.crop.pos.y =
1584 t->output.crop.pos.y + t->output.crop.h
1585 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1586 else if (stripe & DOWN_STRIPE)
1587 task->output.crop.pos.y =
1588 t->output.crop.pos.y + t->output.crop.h
1589 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1591 case IPU_ROTATE_90_RIGHT:
1592 if (stripe & UP_STRIPE)
1593 task->output.crop.pos.x =
1594 t->output.crop.pos.x + t->output.crop.w
1595 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1596 else if (stripe & DOWN_STRIPE)
1597 task->output.crop.pos.x =
1598 t->output.crop.pos.x + t->output.crop.w
1599 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1600 if (stripe & LEFT_STRIPE)
1601 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1602 else if (stripe & RIGHT_STRIPE)
1603 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1605 case IPU_ROTATE_90_RIGHT_HFLIP:
1606 if (stripe & UP_STRIPE)
1607 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1608 else if (stripe & DOWN_STRIPE)
1609 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1610 if (stripe & LEFT_STRIPE)
1611 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1612 else if (stripe & RIGHT_STRIPE)
1613 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1615 case IPU_ROTATE_90_RIGHT_VFLIP:
1616 if (stripe & UP_STRIPE)
1617 task->output.crop.pos.x =
1618 t->output.crop.pos.x + t->output.crop.w
1619 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1620 else if (stripe & DOWN_STRIPE)
1621 task->output.crop.pos.x =
1622 t->output.crop.pos.x + t->output.crop.w
1623 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1624 if (stripe & LEFT_STRIPE)
1625 task->output.crop.pos.y =
1626 t->output.crop.pos.y + t->output.crop.h
1627 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1628 else if (stripe & RIGHT_STRIPE)
1629 task->output.crop.pos.y =
1630 t->output.crop.pos.y + t->output.crop.h
1631 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1633 case IPU_ROTATE_90_LEFT:
1634 if (stripe & UP_STRIPE)
1635 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1636 else if (stripe & DOWN_STRIPE)
1637 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1638 if (stripe & LEFT_STRIPE)
1639 task->output.crop.pos.y =
1640 t->output.crop.pos.y + t->output.crop.h
1641 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1642 else if (stripe & RIGHT_STRIPE)
1643 task->output.crop.pos.y =
1644 t->output.crop.pos.y + t->output.crop.h
1645 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1648 dev_err(t->dev, "ERR:should not be here\n");
1652 ret = create_split_child_task(sp_task);
1654 dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
1658 static int queue_split_task(struct ipu_task_entry *t,
1659 struct ipu_split_task *sp_task, uint32_t size)
1664 struct ipu_task_entry *tsk = NULL;
1665 struct mutex *lock = &t->split_lock;
1667 dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
1668 t, t->task_no, size);
1670 init_waitqueue_head(&t->split_waitq);
1671 INIT_LIST_HEAD(&t->split_list);
1672 for (j = 0; j < size; j++) {
1673 memset(&sp_task[j], 0, sizeof(*sp_task));
1674 sp_task[j].parent_task = t;
1675 sp_task[j].task_no = t->task_no;
1678 if (t->set.split_mode == RL_SPLIT) {
1680 err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
1684 err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
1685 } else if (t->set.split_mode == UD_SPLIT) {
1687 err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
1691 err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
1694 err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1698 err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1702 err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
1706 err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
1710 for (j = 0; j < (i + 1); j++) {
1712 if (sp_task[j].child_task)
1714 "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
1715 j, sp_task[j].child_task->task_no,
1716 sp_task[j].child_task->state, err[j]);
1719 dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
1720 sp_task[j].child_task, j, sp_task[j].child_task->task_no,
1721 state_msg[sp_task[j].child_task->state].msg, err[j]);
1727 for (j = 0; j < (i + 1); j++) {
1728 if (err[j] < 0 && !ret)
1730 tsk = sp_task[j].child_task;
1734 memset(tsk, 0, sizeof(*tsk));
1736 t->state = STATE_ERR;
1741 static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
1742 ipu_channel_t channel, uint32_t ch_type)
1747 dma_addr_t inbuf_base = 0;
1749 struct vdoa_params param;
1750 struct vdoa_ipu_buf buf;
1751 struct ipu_soc *ipu_idx;
1752 u32 ipu_stride, obuf_size;
1756 if ((IPU_PIX_FMT_YUYV != t->output.format) &&
1757 (IPU_PIX_FMT_NV12 != t->output.format)) {
1758 dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
1762 memset(¶m, 0, sizeof(param));
1763 /* init channel tiled bufs */
1764 if (deinterlace_3_field(t) &&
1765 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1766 field_size = tiled_filed_size(t);
1767 if (INPUT_CHAN_VDI_P == ch_type) {
1768 inbuf_base = t->input.paddr + field_size;
1769 param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
1770 } else if (INPUT_CHAN == ch_type) {
1771 inbuf_base = t->input.paddr_n;
1772 param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
1773 } else if (INPUT_CHAN_VDI_N == ch_type) {
1774 inbuf_base = t->input.paddr_n + field_size;
1775 param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
1778 height = t->input.crop.h >> 1; /* field format for vdoa */
1779 width = t->input.crop.w;
1780 param.vfield_buf.vubo = t->set.i_uoff;
1781 param.interlaced = 1;
1782 param.scan_order = 1;
1783 type = IPU_INPUT_BUFFER;
1784 } else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
1785 (INPUT_CHAN == ch_type)) {
1786 height = t->input.crop.h;
1787 width = t->input.crop.w;
1788 param.vframe_buf.veba = t->input.paddr + t->set.i_off;
1789 param.vframe_buf.vubo = t->set.i_uoff;
1790 type = IPU_INPUT_BUFFER;
1794 param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
1795 if (param.band_mode && (t->set.band_lines != 3) &&
1796 (t->set.band_lines != 4) && (t->set.band_lines != 5))
1798 else if (param.band_mode)
1799 param.band_lines = (1 << t->set.band_lines);
1800 for (i = 0; i < max_ipu_no; i++) {
1801 ipu_idx = ipu_get_soc(i);
1802 if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
1805 if (t->set.task & VDOA_ONLY)
1806 /* dummy, didn't need ipu res */
1808 if (max_ipu_no == i) {
1809 dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
1814 param.vpu_stride = t->input.width;
1815 param.height = height;
1816 param.width = width;
1817 if (IPU_PIX_FMT_NV12 == t->output.format)
1818 param.pfs = VDOA_PFS_NV12;
1820 param.pfs = VDOA_PFS_YUYV;
1821 ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
1823 ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
1824 obuf_size = PAGE_ALIGN(param.width * param.height *
1825 fmt_to_bpp(ipu_fmt)/8);
1826 dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
1827 param.band_mode, param.band_lines);
1828 if (!param.band_mode) {
1829 /* note: if only for tiled -> raster convert and
1830 no other post-processing, we don't need alloc buf
1831 and use output buffer directly.
1833 if (t->set.task & VDOA_ONLY)
1834 param.ieba0 = t->output.paddr;
1836 dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
1840 if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
1841 dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
1845 ret = vdoa_setup(t->vdoa_handle, ¶m);
1848 vdoa_get_output_buf(t->vdoa_handle, &buf);
1849 if (t->set.task & VDOA_ONLY)
1852 ret = ipu_init_channel_buffer(ipu,
1866 t->state = STATE_INIT_CHAN_BUF_FAIL;
1870 if (param.band_mode) {
1871 ret = ipu_set_channel_bandmode(ipu, channel,
1872 type, t->set.band_lines);
1874 t->state = STATE_INIT_CHAN_BAND_FAIL;
1882 static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
1886 if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
1887 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1888 CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
1889 } else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
1890 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1891 CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
1892 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
1894 CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
1895 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
1897 CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
1900 dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n",
1901 t->task_no, t->input.format);
1908 static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
1911 ipu_channel_params_t params;
1912 dma_addr_t inbuf = 0, ovbuf = 0, ov_alp_buf = 0;
1913 dma_addr_t inbuf_p = 0, inbuf_n = 0;
1914 dma_addr_t outbuf = 0;
1915 int out_uoff = 0, out_voff = 0, out_rot;
1916 int out_w = 0, out_h = 0, out_stride;
1918 u32 vdi_frame_idx = 0;
1920 memset(¶ms, 0, sizeof(params));
1922 /* is it need link a rot channel */
1923 if (ic_and_rot(t->set.mode)) {
1924 outbuf = t->set.r_paddr;
1925 out_w = t->set.r_width;
1926 out_h = t->set.r_height;
1927 out_stride = t->set.r_stride;
1928 out_fmt = t->set.r_fmt;
1931 out_rot = IPU_ROTATE_NONE;
1933 outbuf = t->output.paddr + t->set.o_off;
1934 out_w = t->output.crop.w;
1935 out_h = t->output.crop.h;
1936 out_stride = t->set.ostride;
1937 out_fmt = t->output.format;
1938 out_uoff = t->set.o_uoff;
1939 out_voff = t->set.o_voff;
1940 out_rot = t->output.rotate;
1944 params.mem_prp_vf_mem.in_width = t->input.crop.w;
1945 params.mem_prp_vf_mem.out_width = out_w;
1946 params.mem_prp_vf_mem.in_height = t->input.crop.h;
1947 params.mem_prp_vf_mem.out_height = out_h;
1948 params.mem_prp_vf_mem.in_pixel_fmt = t->input.format;
1949 params.mem_prp_vf_mem.out_pixel_fmt = out_fmt;
1950 params.mem_prp_vf_mem.motion_sel = t->input.deinterlace.motion;
1952 params.mem_prp_vf_mem.outh_resize_ratio =
1953 t->set.sp_setting.outh_resize_ratio;
1954 params.mem_prp_vf_mem.outv_resize_ratio =
1955 t->set.sp_setting.outv_resize_ratio;
1957 if (t->overlay_en) {
1958 params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
1959 params.mem_prp_vf_mem.graphics_combine_en = 1;
1960 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
1961 params.mem_prp_vf_mem.global_alpha_en = 1;
1962 else if (t->overlay.alpha.loc_alp_paddr)
1963 params.mem_prp_vf_mem.alpha_chan_en = 1;
1964 /* otherwise, alpha bending per pixel is used. */
1965 params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
1966 if (t->overlay.colorkey.enable) {
1967 params.mem_prp_vf_mem.key_color_en = 1;
1968 params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
1972 if (t->input.deinterlace.enable) {
1973 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_FIELD_MASK)
1974 params.mem_prp_vf_mem.field_fmt =
1975 IPU_DEINTERLACE_FIELD_BOTTOM;
1977 params.mem_prp_vf_mem.field_fmt =
1978 IPU_DEINTERLACE_FIELD_TOP;
1980 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
1981 vdi_frame_idx = t->input.deinterlace.field_fmt &
1982 IPU_DEINTERLACE_RATE_FRAME1;
1985 if (t->set.mode & VDOA_MODE)
1989 if (!(t->set.task & VDOA_ONLY)) {
1990 ret = ipu_init_channel(ipu, t->set.ic_chan, ¶ms);
1992 t->state = STATE_INIT_CHAN_FAIL;
1997 if (deinterlace_3_field(t)) {
1998 ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, ¶ms);
2000 t->state = STATE_INIT_CHAN_FAIL;
2003 ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, ¶ms);
2005 t->state = STATE_INIT_CHAN_FAIL;
2010 /* init channel bufs */
2011 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
2012 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
2013 ret = init_tiled_ch_bufs(ipu, t);
2017 if ((deinterlace_3_field(t)) &&
2018 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2019 if (params.mem_prp_vf_mem.field_fmt ==
2020 IPU_DEINTERLACE_FIELD_TOP) {
2021 if (vdi_frame_idx) {
2022 inbuf_p = t->input.paddr + t->set.istride +
2024 inbuf = t->input.paddr_n + t->set.i_off;
2025 inbuf_n = t->input.paddr_n + t->set.istride +
2027 params.mem_prp_vf_mem.field_fmt =
2028 IPU_DEINTERLACE_FIELD_BOTTOM;
2030 inbuf_p = t->input.paddr + t->set.i_off;
2031 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2032 inbuf_n = t->input.paddr_n + t->set.i_off;
2035 if (vdi_frame_idx) {
2036 inbuf_p = t->input.paddr + t->set.i_off;
2037 inbuf = t->input.paddr_n + t->set.istride + t->set.i_off;
2038 inbuf_n = t->input.paddr_n + t->set.i_off;
2039 params.mem_prp_vf_mem.field_fmt =
2040 IPU_DEINTERLACE_FIELD_TOP;
2042 inbuf_p = t->input.paddr + t->set.istride +
2044 inbuf = t->input.paddr + t->set.i_off;
2045 inbuf_n = t->input.paddr_n + t->set.istride +
2050 if (t->input.deinterlace.enable) {
2051 if (params.mem_prp_vf_mem.field_fmt ==
2052 IPU_DEINTERLACE_FIELD_TOP) {
2053 if (vdi_frame_idx) {
2054 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2055 params.mem_prp_vf_mem.field_fmt =
2056 IPU_DEINTERLACE_FIELD_BOTTOM;
2058 inbuf = t->input.paddr + t->set.i_off;
2060 if (vdi_frame_idx) {
2061 inbuf = t->input.paddr + t->set.i_off;
2062 params.mem_prp_vf_mem.field_fmt =
2063 IPU_DEINTERLACE_FIELD_TOP;
2065 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2068 inbuf = t->input.paddr + t->set.i_off;
2072 ovbuf = t->overlay.paddr + t->set.ov_off;
2074 if (t->overlay_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
2075 ov_alp_buf = t->overlay.alpha.loc_alp_paddr
2076 + t->set.ov_alpha_off;
2078 if ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
2079 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2080 ret = ipu_init_channel_buffer(ipu,
2094 t->state = STATE_INIT_CHAN_BUF_FAIL;
2098 if (deinterlace_3_field(t) &&
2099 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2100 ret = ipu_init_channel_buffer(ipu,
2101 t->set.vdi_ic_p_chan,
2114 t->state = STATE_INIT_CHAN_BUF_FAIL;
2118 ret = ipu_init_channel_buffer(ipu,
2119 t->set.vdi_ic_n_chan,
2132 t->state = STATE_INIT_CHAN_BUF_FAIL;
2137 if (t->overlay_en) {
2138 ret = ipu_init_channel_buffer(ipu,
2140 IPU_GRAPH_IN_BUFFER,
2152 t->state = STATE_INIT_CHAN_BUF_FAIL;
2157 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2158 ret = ipu_init_channel_buffer(ipu,
2160 IPU_ALPHA_IN_BUFFER,
2161 IPU_PIX_FMT_GENERIC,
2164 t->set.ov_alpha_stride,
2171 t->state = STATE_INIT_CHAN_BUF_FAIL;
2176 if (!(t->set.task & VDOA_ONLY)) {
2177 ret = ipu_init_channel_buffer(ipu,
2191 t->state = STATE_INIT_CHAN_BUF_FAIL;
2196 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2197 ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2198 CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
2199 STATE_LINK_CHAN_FAIL, done, ret);
2206 static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
2210 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2211 ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2212 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
2213 STATE_UNLINK_CHAN_FAIL, ret);
2215 ipu_uninit_channel(ipu, t->set.ic_chan);
2216 if (deinterlace_3_field(t)) {
2217 ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
2218 ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
2222 static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2225 dma_addr_t inbuf = 0, outbuf = 0;
2226 int in_uoff = 0, in_voff = 0;
2227 int in_fmt, in_width, in_height, in_stride;
2230 ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
2232 t->state = STATE_INIT_CHAN_FAIL;
2236 /* init channel buf */
2237 /* is it need link to a ic channel */
2238 if (ic_and_rot(t->set.mode)) {
2239 in_fmt = t->set.r_fmt;
2240 in_width = t->set.r_width;
2241 in_height = t->set.r_height;
2242 in_stride = t->set.r_stride;
2243 inbuf = t->set.r_paddr;
2247 in_fmt = t->input.format;
2248 in_width = t->input.crop.w;
2249 in_height = t->input.crop.h;
2250 in_stride = t->set.istride;
2251 inbuf = t->input.paddr + t->set.i_off;
2252 in_uoff = t->set.i_uoff;
2253 in_voff = t->set.i_voff;
2255 outbuf = t->output.paddr + t->set.o_off;
2257 ret = ipu_init_channel_buffer(ipu,
2271 t->state = STATE_INIT_CHAN_BUF_FAIL;
2275 ret = ipu_init_channel_buffer(ipu,
2289 t->state = STATE_INIT_CHAN_BUF_FAIL;
2297 static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2299 ipu_uninit_channel(ipu, t->set.rot_chan);
2302 static int get_irq(struct ipu_task_entry *t)
2307 if (only_ic(t->set.mode))
2308 chan = t->set.ic_chan;
2310 chan = t->set.rot_chan;
2313 case MEM_ROT_VF_MEM:
2314 irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
2316 case MEM_ROT_PP_MEM:
2317 irq = IPU_IRQ_PP_ROT_OUT_EOF;
2319 case MEM_VDI_PRP_VF_MEM:
2320 case MEM_PRP_VF_MEM:
2321 irq = IPU_IRQ_PRP_VF_OUT_EOF;
2324 irq = IPU_IRQ_PP_OUT_EOF;
2327 irq = IPU_IRQ_VDIC_OUT_EOF;
2336 static irqreturn_t task_irq_handler(int irq, void *dev_id)
2338 struct ipu_task_entry *prev_tsk = dev_id;
2340 CHECK_PERF(&prev_tsk->ts_inirq);
2341 complete(&prev_tsk->irq_comp);
2342 dev_dbg(prev_tsk->dev, "[0x%p] no-0x%x in-irq!",
2343 prev_tsk, prev_tsk->task_no);
2348 /* Fix deinterlace up&down split mode medium line */
2349 static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
2356 unsigned char *base_off;
2357 struct ipu_task_entry *parent = t->parent;
2360 dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
2363 stripe_mode = t->task_no & 0xf;
2364 task_no = t->task_no >> 4;
2366 base_off = (char *) __va(t->output.paddr);
2367 if (base_off == NULL) {
2368 dev_err(t->dev, "ERR[0x%p]Falied get vitual address\n", t);
2372 vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
2373 vdi_size = vdi_save_lines * t->output.crop.w * 2;
2375 if (vdi_save_lines <= 0) {
2376 dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
2380 /*check vditmpbuf buffer have alloced or buffer size is changed */
2381 if ((vdi_save_lines != parent->old_save_lines) ||
2382 (vdi_size != parent->old_size)) {
2383 if (parent->vditmpbuf[0] != NULL)
2384 kfree(parent->vditmpbuf[0]);
2385 if (parent->vditmpbuf[1] != NULL)
2386 kfree(parent->vditmpbuf[1]);
2388 parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
2389 if (parent->vditmpbuf[0] == NULL) {
2391 "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
2394 memset(parent->vditmpbuf[0], 0, vdi_size);
2396 parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
2397 if (parent->vditmpbuf[1] == NULL) {
2399 "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
2402 memset(parent->vditmpbuf[1], 0, vdi_size);
2404 parent->old_save_lines = vdi_save_lines;
2405 parent->old_size = vdi_size;
2408 /* UP stripe or UP&LEFT stripe */
2409 if ((stripe_mode == UP_STRIPE) ||
2410 (stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
2411 if (!parent->buf0filled) {
2412 offset_addr = t->set.o_off +
2413 t->set.sp_setting.ud_split_line*t->set.ostride;
2414 dmac_flush_range(base_off + offset_addr,
2415 base_off + offset_addr + vdi_size);
2416 outer_flush_range(t->output.paddr + offset_addr,
2417 t->output.paddr + offset_addr + vdi_size);
2419 for (i = 0; i < vdi_save_lines; i++)
2420 memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
2421 base_off + offset_addr +
2422 i*t->set.ostride, t->output.crop.w*2);
2423 parent->buf0filled = true;
2425 offset_addr = t->set.o_off + (t->output.crop.h -
2426 vdi_save_lines) * t->set.ostride;
2427 for (i = 0; i < vdi_save_lines; i++)
2428 memcpy(base_off + offset_addr + i*t->set.ostride,
2429 parent->vditmpbuf[0] + i*t->output.crop.w*2,
2430 t->output.crop.w*2);
2432 dmac_flush_range(base_off + offset_addr,
2433 base_off + offset_addr + i*t->set.ostride);
2434 outer_flush_range(t->output.paddr + offset_addr,
2435 t->output.paddr + offset_addr + i*t->set.ostride);
2436 parent->buf0filled = false;
2439 /*Down stripe or Down&Left stripe*/
2440 else if ((stripe_mode == DOWN_STRIPE) ||
2441 (stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
2442 if (!parent->buf0filled) {
2443 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2444 dmac_flush_range(base_off + offset_addr,
2445 base_off + offset_addr + vdi_size);
2446 outer_flush_range(t->output.paddr + offset_addr,
2447 t->output.paddr + offset_addr + vdi_size);
2449 for (i = 0; i < vdi_save_lines; i++)
2450 memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
2451 base_off + offset_addr + i*t->set.ostride,
2452 t->output.crop.w*2);
2453 parent->buf0filled = true;
2455 offset_addr = t->set.o_off;
2456 for (i = 0; i < vdi_save_lines; i++)
2457 memcpy(base_off + offset_addr + i*t->set.ostride,
2458 parent->vditmpbuf[0] + i*t->output.crop.w*2,
2459 t->output.crop.w*2);
2461 dmac_flush_range(base_off + offset_addr,
2462 base_off + offset_addr + i*t->set.ostride);
2463 outer_flush_range(t->output.paddr + offset_addr,
2464 t->output.paddr + offset_addr + i*t->set.ostride);
2465 parent->buf0filled = false;
2469 else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
2470 if (!parent->buf1filled) {
2471 offset_addr = t->set.o_off +
2472 t->set.sp_setting.ud_split_line*t->set.ostride;
2473 dmac_flush_range(base_off + offset_addr,
2474 base_off + offset_addr + vdi_size);
2475 outer_flush_range(t->output.paddr + offset_addr,
2476 t->output.paddr + offset_addr + vdi_size);
2478 for (i = 0; i < vdi_save_lines; i++)
2479 memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
2480 base_off + offset_addr + i*t->set.ostride,
2481 t->output.crop.w*2);
2482 parent->buf1filled = true;
2484 offset_addr = t->set.o_off +
2485 (t->output.crop.h - vdi_save_lines)*t->set.ostride;
2486 for (i = 0; i < vdi_save_lines; i++)
2487 memcpy(base_off + offset_addr + i*t->set.ostride,
2488 parent->vditmpbuf[1] + i*t->output.crop.w*2,
2489 t->output.crop.w*2);
2491 dmac_flush_range(base_off + offset_addr,
2492 base_off + offset_addr + i*t->set.ostride);
2493 outer_flush_range(t->output.paddr + offset_addr,
2494 t->output.paddr + offset_addr + i*t->set.ostride);
2495 parent->buf1filled = false;
2498 /*Down stripe or Down&Right stript*/
2499 else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
2500 if (!parent->buf1filled) {
2501 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2502 dmac_flush_range(base_off + offset_addr,
2503 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2504 outer_flush_range(t->output.paddr + offset_addr,
2505 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2507 for (i = 0; i < vdi_save_lines; i++)
2508 memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
2509 base_off + offset_addr + i*t->set.ostride,
2510 t->output.crop.w*2);
2511 parent->buf1filled = true;
2513 offset_addr = t->set.o_off;
2514 for (i = 0; i < vdi_save_lines; i++)
2515 memcpy(base_off + offset_addr + i*t->set.ostride,
2516 parent->vditmpbuf[1] + i*t->output.crop.w*2,
2517 t->output.crop.w*2);
2519 dmac_flush_range(base_off + offset_addr,
2520 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2521 outer_flush_range(t->output.paddr + offset_addr,
2522 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2523 parent->buf1filled = false;
2528 static void do_task_release(struct ipu_task_entry *t, int fail)
2531 struct ipu_soc *ipu = t->ipu;
2533 if (t->input.deinterlace.enable && !fail &&
2534 (t->task_no & (UP_STRIPE | DOWN_STRIPE)))
2535 vdi_split_process(ipu, t);
2537 ipu_free_irq(ipu, t->irq, t);
2539 if (t->vdoa_dma.vaddr)
2540 dma_free_coherent(t->dev,
2545 if (only_ic(t->set.mode)) {
2546 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2547 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
2548 STATE_DISABLE_CHAN_FAIL, ret);
2549 if (deinterlace_3_field(t)) {
2550 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2552 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_p",
2553 STATE_DISABLE_CHAN_FAIL, ret);
2554 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2556 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_n",
2557 STATE_DISABLE_CHAN_FAIL, ret);
2559 } else if (only_rot(t->set.mode)) {
2560 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2561 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_rot",
2562 STATE_DISABLE_CHAN_FAIL, ret);
2563 } else if (ic_and_rot(t->set.mode)) {
2564 ret = ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan);
2565 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch",
2566 STATE_UNLINK_CHAN_FAIL, ret);
2567 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2568 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-rot",
2569 STATE_DISABLE_CHAN_FAIL, ret);
2570 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2571 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-ic",
2572 STATE_DISABLE_CHAN_FAIL, ret);
2573 if (deinterlace_3_field(t)) {
2574 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2576 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-p",
2577 STATE_DISABLE_CHAN_FAIL, ret);
2578 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2580 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-n",
2581 STATE_DISABLE_CHAN_FAIL, ret);
2585 if (only_ic(t->set.mode))
2587 else if (only_rot(t->set.mode))
2589 else if (ic_and_rot(t->set.mode)) {
2594 t->state = STATE_OK;
2595 CHECK_PERF(&t->ts_rel);
2599 static void do_task_vdoa_only(struct ipu_task_entry *t)
2603 ret = init_tiled_ch_bufs(NULL, t);
2604 CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
2605 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2606 vdoa_stop(t->vdoa_handle);
2607 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
2608 STATE_VDOA_IRQ_TIMEOUT, out, ret);
2610 t->state = STATE_OK;
2615 static void do_task(struct ipu_task_entry *t)
2621 struct ipu_soc *ipu = t->ipu;
2623 CHECK_PERF(&t->ts_dotask);
2626 t->state = STATE_NO_IPU;
2630 init_completion(&t->irq_comp);
2631 dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
2632 t->task_no, t->task_id);
2635 if (t->set.task & IC_PP) {
2636 t->set.ic_chan = MEM_PP_MEM;
2637 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
2638 } else if (t->set.task & IC_VF) {
2639 t->set.ic_chan = MEM_PRP_VF_MEM;
2640 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
2641 } else if (t->set.task & VDI_VF) {
2642 if (t->set.mode & VDOA_BAND_MODE) {
2643 t->set.ic_chan = MEM_VDI_MEM;
2644 if (deinterlace_3_field(t)) {
2645 t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
2646 t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
2648 dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
2651 t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
2652 if (deinterlace_3_field(t)) {
2653 t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
2654 t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
2657 "[0x%p]ic ch MEM_VDI_PRP_VF_MEM\n", t);
2661 if (t->set.task & ROT_PP) {
2662 t->set.rot_chan = MEM_ROT_PP_MEM;
2663 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
2664 } else if (t->set.task & ROT_VF) {
2665 t->set.rot_chan = MEM_ROT_VF_MEM;
2666 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
2669 if (t->task_id == IPU_TASK_ID_VF)
2670 busy = ic_vf_pp_is_busy(ipu, true);
2671 else if (t->task_id == IPU_TASK_ID_PP)
2672 busy = ic_vf_pp_is_busy(ipu, false);
2674 dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n",
2675 t->task_no, t->task_id);
2679 dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n",
2680 (void *)t, t->task_no, t->task_id);
2681 t->state = STATE_IPU_BUSY;
2687 t->state = STATE_NO_IRQ;
2693 if (only_ic(t->set.mode)) {
2694 dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
2695 ret = init_ic(ipu, t);
2696 CHECK_RETCODE(ret < 0, "init_ic only_ic",
2697 t->state, chan_setup, ret);
2698 } else if (only_rot(t->set.mode)) {
2699 dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
2700 ret = init_rot(ipu, t);
2701 CHECK_RETCODE(ret < 0, "init_rot only_rot",
2702 t->state, chan_setup, ret);
2703 } else if (ic_and_rot(t->set.mode)) {
2704 int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1;
2706 dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
2707 t->set.r_fmt = t->output.format;
2708 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
2709 t->set.r_width = t->output.crop.h;
2710 t->set.r_height = t->output.crop.w;
2712 t->set.r_width = t->output.crop.w;
2713 t->set.r_height = t->output.crop.h;
2715 t->set.r_stride = t->set.r_width *
2716 bytes_per_pixel(t->set.r_fmt);
2717 r_size = PAGE_ALIGN(t->set.r_width * t->set.r_height
2718 * fmt_to_bpp(t->set.r_fmt)/8);
2720 if (r_size > ipu->rot_dma[rot_idx].size) {
2721 dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t);
2723 if (ipu->rot_dma[rot_idx].vaddr)
2724 dma_free_coherent(t->dev,
2725 ipu->rot_dma[rot_idx].size,
2726 ipu->rot_dma[rot_idx].vaddr,
2727 ipu->rot_dma[rot_idx].paddr);
2729 ipu->rot_dma[rot_idx].size = r_size;
2730 ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev,
2732 &ipu->rot_dma[rot_idx].paddr,
2733 GFP_DMA | GFP_KERNEL);
2734 CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
2735 "ic_and_rot", STATE_SYS_NO_MEM,
2736 chan_setup, -ENOMEM);
2738 t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
2740 dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
2741 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
2742 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
2743 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
2744 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
2745 dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
2747 ret = init_ic(ipu, t);
2748 CHECK_RETCODE(ret < 0, "init_ic ic_and_rot",
2749 t->state, chan_setup, ret);
2750 ret = init_rot(ipu, t);
2751 CHECK_RETCODE(ret < 0, "init_rot ic_and_rot",
2752 t->state, chan_setup, ret);
2753 ret = ipu_link_channels(ipu, t->set.ic_chan,
2755 CHECK_RETCODE(ret < 0, "ipu_link_ch ic_and_rot",
2756 STATE_LINK_CHAN_FAIL, chan_setup, ret);
2758 dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t);
2759 t->state = STATE_ERR;
2763 ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, t);
2764 CHECK_RETCODE(ret < 0, "ipu_req_irq",
2765 STATE_IRQ_FAIL, chan_setup, ret);
2767 /* enable/start channel */
2768 if (only_ic(t->set.mode)) {
2769 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2770 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic",
2771 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2772 if (deinterlace_3_field(t)) {
2773 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2774 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_p",
2775 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2776 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2777 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_n",
2778 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2781 ret = ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER,
2783 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic",
2784 STATE_SEL_BUF_FAIL, chan_buf, ret);
2785 if (t->overlay_en) {
2786 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2787 IPU_GRAPH_IN_BUFFER, 0);
2788 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_g",
2789 STATE_SEL_BUF_FAIL, chan_buf, ret);
2790 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2791 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2792 IPU_ALPHA_IN_BUFFER, 0);
2793 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_a",
2794 STATE_SEL_BUF_FAIL, chan_buf,
2798 if (!(t->set.mode & VDOA_BAND_MODE)) {
2799 if (deinterlace_3_field(t))
2800 ipu_select_multi_vdi_buffer(ipu, 0);
2802 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2803 IPU_INPUT_BUFFER, 0);
2804 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
2805 STATE_SEL_BUF_FAIL, chan_buf, ret);
2808 } else if (only_rot(t->set.mode)) {
2809 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2810 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_rot",
2811 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2812 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2813 IPU_OUTPUT_BUFFER, 0);
2814 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_o",
2815 STATE_SEL_BUF_FAIL, chan_buf, ret);
2816 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2817 IPU_INPUT_BUFFER, 0);
2818 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_i",
2819 STATE_SEL_BUF_FAIL, chan_buf, ret);
2820 } else if (ic_and_rot(t->set.mode)) {
2821 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2822 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-rot",
2823 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2824 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2825 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-ic",
2826 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2827 if (deinterlace_3_field(t)) {
2828 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2829 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-p",
2830 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2831 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2832 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-n",
2833 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2836 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2837 IPU_OUTPUT_BUFFER, 0);
2838 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-rot-o",
2839 STATE_SEL_BUF_FAIL, chan_buf, ret);
2840 if (t->overlay_en) {
2841 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2842 IPU_GRAPH_IN_BUFFER, 0);
2843 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-g",
2844 STATE_SEL_BUF_FAIL, chan_buf, ret);
2845 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2846 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2847 IPU_ALPHA_IN_BUFFER, 0);
2848 CHECK_RETCODE(ret < 0, "ipu_sel_buf icrot-ic-a",
2853 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2854 IPU_OUTPUT_BUFFER, 0);
2855 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-o",
2856 STATE_SEL_BUF_FAIL, chan_buf, ret);
2857 if (deinterlace_3_field(t))
2858 ipu_select_multi_vdi_buffer(ipu, 0);
2860 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2861 IPU_INPUT_BUFFER, 0);
2862 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-i",
2863 STATE_SEL_BUF_FAIL, chan_buf, ret);
2868 t->state = STATE_IN_PROGRESS;
2870 if (t->set.mode & VDOA_BAND_MODE) {
2871 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2872 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
2873 STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
2876 CHECK_PERF(&t->ts_waitirq);
2877 ret = wait_for_completion_timeout(&t->irq_comp,
2878 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
2879 CHECK_PERF(&t->ts_wakeup);
2880 CHECK_RETCODE(ret == 0, "wait_for_comp_timeout",
2881 STATE_IRQ_TIMEOUT, chan_rel, ret);
2882 dev_dbg(t->dev, "[0x%p] no-0x%x ipu irq done!", t, t->task_no);
2888 if (t->set.mode & VDOA_BAND_MODE)
2889 vdoa_stop(t->vdoa_handle);
2890 do_task_release(t, t->state >= STATE_ERR);
2894 static void do_task_vdoa_vdi(struct ipu_task_entry *t)
2900 /* FIXME: crop mode not support now */
2901 stripe_width = t->input.width >> 1;
2902 t->input.crop.pos.x = 0;
2903 t->input.crop.pos.y = 0;
2904 t->input.crop.w = stripe_width;
2905 t->input.crop.h = t->input.height;
2906 t->output.crop.w = stripe_width;
2907 t->output.crop.h = t->input.height;
2909 for (i = 0; i < 2; i++) {
2910 t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
2911 t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
2913 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
2919 update_offset(t->input.format,
2920 t->input.width, t->input.height,
2921 t->input.crop.pos.x,
2922 t->input.crop.pos.y,
2923 &t->set.i_off, &t->set.i_uoff,
2924 &t->set.i_voff, &t->set.istride);
2925 dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
2926 t->set.i_off, t->set.i_uoff, t->set.istride);
2928 ret = set_crop(&t->output.crop, t->input.width,
2929 t->output.height, t->output.format);
2934 update_offset(t->output.format,
2935 t->output.width, t->output.height,
2936 t->output.crop.pos.x,
2937 t->output.crop.pos.y,
2938 &t->set.o_off, &t->set.o_uoff,
2939 &t->set.o_voff, &t->set.ostride);
2941 dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
2942 t->set.o_off, t->set.o_uoff, t->set.ostride);
2949 dev_err(t->dev, "ERR %s set_crop.\n", __func__);
2954 static void get_res_do_task(struct ipu_task_entry *t)
2957 uint32_t split_child;
2960 found = get_vdoa_ipu_res(t);
2962 dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n",
2966 if (t->set.task & VDOA_ONLY)
2967 do_task_vdoa_only(t);
2968 else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
2969 (t->set.mode & VDOA_BAND_MODE) &&
2970 (t->input.crop.w > soc_max_vdi_in_width()))
2971 do_task_vdoa_vdi(t);
2974 put_vdoa_ipu_res(t, 0);
2976 if (t->state != STATE_OK) {
2977 dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
2978 t, t->task_no, state_msg[t->state].msg);
2981 split_child = need_split(t) && t->parent;
2983 lock = &t->parent->split_lock;
2987 wake_up(&t->parent->split_waitq);
2993 static void wait_split_task_complete(struct ipu_task_entry *parent,
2994 struct ipu_split_task *sp_task, uint32_t size)
2996 struct ipu_task_entry *tsk = NULL;
2999 unsigned long flags;
3000 struct mutex *lock = &parent->split_lock;
3001 int k, busy_vf, busy_pp;
3002 struct ipu_soc *ipu;
3005 for (j = 0; j < size; j++) {
3006 rc = wait_event_timeout(
3007 parent->split_waitq,
3008 sp_task_check_done(sp_task, parent, size, &idx),
3009 msecs_to_jiffies(parent->timeout - DEF_DELAY_MS));
3011 dev_err(parent->dev,
3012 "ERR:[0x%p] no-0x%x, split_task timeout,j:%d,"
3014 parent, parent->task_no, j, size);
3019 dev_err(parent->dev,
3020 "ERR:[0x%p] no-0x%x, invalid task idx:%d\n",
3021 parent, parent->task_no, idx);
3024 tsk = sp_task[idx].child_task;
3026 if (!tsk->split_done || !tsk->ipu)
3028 "ERR:no-0x%x,split not done:%d/null ipu:0x%p\n",
3029 tsk->task_no, tsk->split_done, tsk->ipu);
3030 tsk->split_done = 0;
3034 "[0x%p] no-0x%x sp_tsk[%d] done,state:%d.\n",
3035 tsk, tsk->task_no, idx, tsk->state);
3037 CHECK_PERF(&tsk->ts_rel);
3038 PRINT_TASK_STATISTICS;
3044 if (ret == -ETIMEDOUT) {
3046 for (k = 0; k < max_ipu_no; k++) {
3047 ipu = ipu_get_soc(k);
3049 dev_err(parent->dev, "no:0x%x, null ipu:%d\n",
3050 parent->task_no, k);
3052 busy_vf = ic_vf_pp_is_busy(ipu, true);
3053 busy_pp = ic_vf_pp_is_busy(ipu, false);
3054 dev_err(parent->dev,
3055 "ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
3056 k, busy_vf, busy_pp);
3059 for (k = 0; k < size; k++) {
3060 tsk = sp_task[k].child_task;
3063 dev_err(parent->dev,
3064 "ERR: sp_task[%d][0x%p] no-0x%x done:%d,"
3065 "state:%s,on_list:%d, ipu:0x%p,timeout!\n",
3066 k, tsk, tsk->task_no, tsk->split_done,
3067 state_msg[tsk->state].msg, tsk->task_in_list,
3072 for (j = 0; j < size; j++) {
3073 tsk = sp_task[j].child_task;
3076 spin_lock_irqsave(&ipu_task_list_lock, flags);
3077 if (tsk->task_in_list) {
3078 list_del(&tsk->node);
3079 tsk->task_in_list = 0;
3081 "[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
3082 tsk, tsk->task_no, tsk->task_id);
3084 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3087 if (tsk->state != STATE_OK) {
3089 "ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n",
3090 tsk, tsk->task_no, tsk->task_id,
3091 state_msg[tsk->state].msg);
3093 kref_put(&tsk->refcount, task_mem_free);
3096 kfree(parent->vditmpbuf[0]);
3097 kfree(parent->vditmpbuf[1]);
3100 parent->state = STATE_TIMEOUT;
3102 parent->state = STATE_OK;
3106 static inline int find_task(struct ipu_task_entry **t, int thread_id)
3109 unsigned long flags;
3110 struct ipu_task_entry *tsk;
3111 struct list_head *task_list = &ipu_task_list;
3114 spin_lock_irqsave(&ipu_task_list_lock, flags);
3115 found = !list_empty(task_list);
3117 tsk = list_first_entry(task_list, struct ipu_task_entry, node);
3118 if (tsk->task_in_list) {
3119 list_del(&tsk->node);
3120 tsk->task_in_list = 0;
3122 kref_get(&tsk->refcount);
3124 "thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n",
3125 thread_id, tsk, tsk->task_no, tsk->set.mode);
3128 "thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n",
3129 thread_id, tsk->task_no, tsk->set.mode);
3131 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3136 static int ipu_task_thread(void *argv)
3138 struct ipu_task_entry *tsk;
3139 struct ipu_task_entry *sp_tsk0;
3140 struct ipu_split_task sp_task[4];
3141 /* priority lower than irq_thread */
3142 const struct sched_param param = {
3143 .sched_priority = MAX_USER_RT_PRIO/2 - 1,
3148 unsigned long flags;
3150 struct cpumask cpu_mask;
3151 struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
3154 curr_thread_id = thread_id;
3155 sched_setscheduler(current, SCHED_FIFO, ¶m);
3157 if (!data->is_vdoa) {
3158 cpu = cpumask_first(cpu_online_mask);
3159 cpumask_set_cpu(cpu, &cpu_mask);
3160 ret = sched_setaffinity(data->ipu->thread[data->id]->pid,
3163 pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret);
3165 pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu);
3168 while (!kthread_should_stop()) {
3173 wait_event_interruptible(thread_waitq, find_task(&tsk, curr_thread_id));
3176 pr_err("thread:%d can not find task.\n",
3181 /* note: other threads run split child task */
3182 split_parent = need_split(tsk) && !tsk->parent;
3183 split_child = need_split(tsk) && tsk->parent;
3185 if ((tsk->set.split_mode == RL_SPLIT) ||
3186 (tsk->set.split_mode == UD_SPLIT))
3190 ret = queue_split_task(tsk, sp_task, size);
3194 struct list_head *pos;
3196 spin_lock_irqsave(&ipu_task_list_lock, flags);
3198 sp_tsk0 = list_first_entry(&tsk->split_list,
3199 struct ipu_task_entry, node);
3200 list_del(&sp_tsk0->node);
3202 list_for_each(pos, &tsk->split_list) {
3203 struct ipu_task_entry *tmp;
3205 tmp = list_entry(pos,
3206 struct ipu_task_entry, node);
3207 tmp->task_in_list = 1;
3209 "[0x%p] no-0x%x,id:%d sp_tsk "
3210 "add_to_list.\n", tmp,
3211 tmp->task_no, tmp->task_id);
3213 /* add to global list */
3214 list_splice(&tsk->split_list, &ipu_task_list);
3216 spin_unlock_irqrestore(&ipu_task_list_lock,
3218 /* let the parent thread do the first sp_task */
3219 /* FIXME: ensure the correct sequence for split
3223 "ERR: no-0x%x,can not get split_tsk0\n",
3225 wake_up_interruptible(&thread_waitq);
3226 get_res_do_task(sp_tsk0);
3227 dev_dbg(sp_tsk0->dev,
3228 "thread:%d complete tsk no:0x%x.\n",
3229 curr_thread_id, sp_tsk0->task_no);
3230 ret = atomic_read(&req_cnt);
3232 wake_up(&res_waitq);
3233 dev_dbg(sp_tsk0->dev,
3234 "sp_tsk0 sche thread:%d no:0x%x,"
3235 "req_cnt:%d\n", curr_thread_id,
3236 sp_tsk0->task_no, ret);
3237 /* For other threads to get_res */
3242 get_res_do_task(tsk);
3244 /* wait for all 4 sp_task finished here or timeout
3245 and then release all resources */
3246 if (split_parent && !split_fail)
3247 wait_split_task_complete(tsk, sp_task, size);
3250 atomic_inc(&tsk->done);
3251 wake_up(&tsk->task_waitq);
3254 dev_dbg(tsk->dev, "thread:%d complete tsk no:0x%x-[0x%p].\n",
3255 curr_thread_id, tsk->task_no, tsk);
3256 ret = atomic_read(&req_cnt);
3258 wake_up(&res_waitq);
3259 dev_dbg(tsk->dev, "sche thread:%d no:0x%x,req_cnt:%d\n",
3260 curr_thread_id, tsk->task_no, ret);
3261 /* note: give cpu to other threads to get_res */
3265 kref_put(&tsk->refcount, task_mem_free);
3268 pr_info("ERR %s exit.\n", __func__);
3272 int ipu_check_task(struct ipu_task *task)
3274 struct ipu_task_entry *tsk;
3277 tsk = create_task_entry(task);
3279 return PTR_ERR(tsk);
3281 ret = check_task(tsk);
3283 task->input = tsk->input;
3284 task->output = tsk->output;
3285 task->overlay = tsk->overlay;
3286 dump_task_info(tsk);
3288 kref_put(&tsk->refcount, task_mem_free);
3290 pr_debug("%s ret:%d.\n", __func__, ret);
3293 EXPORT_SYMBOL_GPL(ipu_check_task);
3295 int ipu_queue_task(struct ipu_task *task)
3297 struct ipu_task_entry *tsk;
3298 unsigned long flags;
3303 tsk = create_task_entry(task);
3305 return PTR_ERR(tsk);
3307 CHECK_PERF(&tsk->ts_queue);
3308 ret = prepare_task(tsk);
3312 if (need_split(tsk)) {
3313 CHECK_PERF(&tsk->ts_dotask);
3314 CHECK_PERF(&tsk->ts_waitirq);
3315 CHECK_PERF(&tsk->ts_inirq);
3316 CHECK_PERF(&tsk->ts_wakeup);
3319 /* task_no last four bits for split task type*/
3320 tmp_task_no = atomic_inc_return(&frame_no);
3321 tsk->task_no = tmp_task_no << 4;
3322 init_waitqueue_head(&tsk->task_waitq);
3324 spin_lock_irqsave(&ipu_task_list_lock, flags);
3325 list_add_tail(&tsk->node, &ipu_task_list);
3326 tsk->task_in_list = 1;
3327 dev_dbg(tsk->dev, "[0x%p,no-0x%x] list_add_tail\n", tsk, tsk->task_no);
3328 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3329 wake_up_interruptible(&thread_waitq);
3331 ret = wait_event_timeout(tsk->task_waitq, atomic_read(&tsk->done),
3332 msecs_to_jiffies(tsk->timeout));
3334 /* note: the timeout should larger than the internal timeout!*/
3336 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x, timeout:%dms!\n",
3337 tsk, tsk->task_no, tsk->timeout);
3339 if (STATE_OK != tsk->state) {
3340 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x,state %d: %s\n",
3341 tsk, tsk->task_no, tsk->state,
3342 state_msg[tsk->state].msg);
3348 spin_lock_irqsave(&ipu_task_list_lock, flags);
3349 if (tsk->task_in_list) {
3350 list_del(&tsk->node);
3351 tsk->task_in_list = 0;
3352 dev_dbg(tsk->dev, "[0x%p] no:0x%x list_del\n",
3355 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3358 CHECK_PERF(&tsk->ts_rel);
3359 PRINT_TASK_STATISTICS;
3360 if (ts_frame_avg == 0)
3361 ts_frame_avg = ts_frame.tv_nsec / NSEC_PER_USEC +
3362 ts_frame.tv_sec * USEC_PER_SEC;
3364 ts_frame_avg = (ts_frame_avg + ts_frame.tv_nsec / NSEC_PER_USEC
3365 + ts_frame.tv_sec * USEC_PER_SEC)/2;
3366 if (timespec_compare(&ts_frame, &ts_frame_max) > 0)
3367 ts_frame_max = ts_frame;
3369 atomic_inc(&frame_cnt);
3371 if ((atomic_read(&frame_cnt) % 1000) == 0)
3372 pr_debug("ipu_dev: max frame time:%ldus, avg frame time:%dus,"
3373 "frame_cnt:%d\n", ts_frame_max.tv_nsec / NSEC_PER_USEC
3374 + ts_frame_max.tv_sec * USEC_PER_SEC,
3375 ts_frame_avg, atomic_read(&frame_cnt));
3379 dev_err(tsk->dev, "ERR: no-0x%x,ipu_queue_task err:%d\n",
3382 kref_put(&tsk->refcount, task_mem_free);
3386 EXPORT_SYMBOL_GPL(ipu_queue_task);
3388 static int mxc_ipu_open(struct inode *inode, struct file *file)
3390 file->private_data = (void *)atomic_inc_return(&file_index);
3394 static long mxc_ipu_ioctl(struct file *file,
3395 unsigned int cmd, unsigned long arg)
3397 int __user *argp = (void __user *)arg;
3401 case IPU_CHECK_TASK:
3403 struct ipu_task task;
3406 (&task, (struct ipu_task *) arg,
3407 sizeof(struct ipu_task)))
3409 ret = ipu_check_task(&task);
3410 if (copy_to_user((struct ipu_task *) arg,
3411 &task, sizeof(struct ipu_task)))
3415 case IPU_QUEUE_TASK:
3417 struct ipu_task task;
3420 (&task, (struct ipu_task *) arg,
3421 sizeof(struct ipu_task)))
3423 ret = ipu_queue_task(&task);
3429 struct ipu_alloc_list *mem;
3431 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
3435 if (get_user(size, argp))
3438 mem->size = PAGE_ALIGN(size);
3440 mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
3442 GFP_DMA | GFP_KERNEL);
3443 if (mem->cpu_addr == NULL) {
3447 mem->file_index = file->private_data;
3448 mutex_lock(&ipu_alloc_lock);
3449 list_add(&mem->list, &ipu_alloc_list);
3450 mutex_unlock(&ipu_alloc_lock);
3452 dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
3453 mem->size, mem->phy_addr);
3455 if (put_user(mem->phy_addr, argp))
3462 unsigned long offset;
3463 struct ipu_alloc_list *mem;
3465 if (get_user(offset, argp))
3469 mutex_lock(&ipu_alloc_lock);
3470 list_for_each_entry(mem, &ipu_alloc_list, list) {
3471 if (mem->phy_addr == offset) {
3472 list_del(&mem->list);
3473 dma_free_coherent(ipu_dev,
3482 mutex_unlock(&ipu_alloc_lock);
3484 dev_dbg(ipu_dev, "free %d bytes @ 0x%08X\n",
3485 mem->size, mem->phy_addr);
3495 static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
3499 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
3500 struct ipu_alloc_list *mem;
3502 mutex_lock(&ipu_alloc_lock);
3503 list_for_each_entry(mem, &ipu_alloc_list, list) {
3504 if (offset == mem->phy_addr) {
3510 mutex_unlock(&ipu_alloc_lock);
3514 if (vma->vm_end - vma->vm_start > len)
3517 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
3519 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
3520 vma->vm_end - vma->vm_start,
3521 vma->vm_page_prot)) {
3529 static int mxc_ipu_release(struct inode *inode, struct file *file)
3531 struct ipu_alloc_list *mem;
3532 struct ipu_alloc_list *n;
3534 mutex_lock(&ipu_alloc_lock);
3535 list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
3536 if ((mem->cpu_addr != 0) &&
3537 (file->private_data == mem->file_index)) {
3538 list_del(&mem->list);
3539 dma_free_coherent(ipu_dev,
3543 dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
3544 mem->size, mem->phy_addr);
3548 mutex_unlock(&ipu_alloc_lock);
3549 atomic_dec(&file_index);
3554 static struct file_operations mxc_ipu_fops = {
3555 .owner = THIS_MODULE,
3556 .open = mxc_ipu_open,
3557 .mmap = mxc_ipu_mmap,
3558 .release = mxc_ipu_release,
3559 .unlocked_ioctl = mxc_ipu_ioctl,
3562 int register_ipu_device(struct ipu_soc *ipu, int id)
3566 static struct ipu_thread_data thread_data[5];
3569 major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
3571 printk(KERN_ERR "Unable to register mxc_ipu as a char device\n");
3573 goto register_cdev_fail;
3576 ipu_class = class_create(THIS_MODULE, "mxc_ipu");
3577 if (IS_ERR(ipu_class)) {
3578 ret = PTR_ERR(ipu_class);
3579 goto ipu_class_fail;
3582 ipu_dev = device_create(ipu_class, NULL, MKDEV(major, 0),
3584 if (IS_ERR(ipu_dev)) {
3585 ret = PTR_ERR(ipu_dev);
3586 goto dev_create_fail;
3588 ipu_dev->dma_mask = kmalloc(sizeof(*ipu_dev->dma_mask), GFP_KERNEL);
3589 *ipu_dev->dma_mask = DMA_BIT_MASK(32);
3590 ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32);
3592 mutex_init(&ipu_ch_tbl.lock);
3595 ipu->rot_dma[0].size = 0;
3596 ipu->rot_dma[1].size = 0;
3598 thread_data[idx].ipu = ipu;
3599 thread_data[idx].id = 0;
3600 thread_data[idx].is_vdoa = 0;
3601 ipu->thread[0] = kthread_run(ipu_task_thread, &thread_data[idx++],
3603 if (IS_ERR(ipu->thread[0])) {
3604 ret = PTR_ERR(ipu->thread[0]);
3608 thread_data[idx].ipu = ipu;
3609 thread_data[idx].id = 1;
3610 thread_data[idx].is_vdoa = 0;
3611 ipu->thread[1] = kthread_run(ipu_task_thread, &thread_data[idx++],
3613 if (IS_ERR(ipu->thread[1])) {
3614 ret = PTR_ERR(ipu->thread[1]);
3622 kthread_stop(ipu->thread[0]);
3625 device_destroy(ipu_class, MKDEV(major, 0));
3628 class_destroy(ipu_class);
3632 unregister_chrdev(major, "mxc_ipu");
3637 void unregister_ipu_device(struct ipu_soc *ipu, int id)
3641 kthread_stop(ipu->thread[0]);
3642 kthread_stop(ipu->thread[1]);
3643 for (i = 0; i < 2; i++) {
3644 if (ipu->rot_dma[i].vaddr)
3645 dma_free_coherent(ipu_dev,
3646 ipu->rot_dma[i].size,
3647 ipu->rot_dma[i].vaddr,
3648 ipu->rot_dma[i].paddr);
3652 device_destroy(ipu_class, MKDEV(major, 0));
3653 class_destroy(ipu_class);
3654 unregister_chrdev(major, "mxc_ipu");