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");
673 static void dump_check_warn(struct device *dev, int warn)
675 if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
676 dev_warn(dev, "input u/v offset not 8 align\n");
677 if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
678 dev_warn(dev, "output u/v offset not 8 align\n");
679 if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
680 dev_warn(dev, "overlay u/v offset not 8 align\n");
683 static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
685 if ((width == 0) || (height == 0)) {
686 pr_err("Invalid param: width=%d, height=%d\n", width, height);
690 if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
691 (IPU_PIX_FMT_TILED_NV12F == fmt)) {
692 if (crop->w || crop->h) {
693 if (((crop->w + crop->pos.x) > width)
694 || ((crop->h + crop->pos.y) > height)
695 || (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
696 || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
697 || (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
698 || (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
700 pr_err("set_crop error MB align.\n");
708 if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
709 || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
710 pr_err("set_crop error w/h MB align.\n");
715 if (crop->w || crop->h) {
716 if (((crop->w + crop->pos.x) > width)
717 || ((crop->h + crop->pos.y) > height))
725 crop->w -= crop->w%8;
726 crop->h -= crop->h%8;
729 if ((crop->w == 0) || (crop->h == 0)) {
730 pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
738 static void update_offset(unsigned int fmt,
739 unsigned int width, unsigned int height,
740 unsigned int pos_x, unsigned int pos_y,
741 int *off, int *uoff, int *voff, int *stride)
743 /* NOTE: u v offset should based on start point of off*/
745 case IPU_PIX_FMT_YUV420P2:
746 case IPU_PIX_FMT_YUV420P:
747 *off = pos_y * width + pos_x;
748 *uoff = (width * (height - pos_y) - pos_x)
749 + (width/2) * (pos_y/2) + pos_x/2;
750 /* In case height is odd, round up to even */
751 *voff = *uoff + (width/2) * ((height+1)/2);
753 case IPU_PIX_FMT_YVU420P:
754 *off = pos_y * width + pos_x;
755 *voff = (width * (height - pos_y) - pos_x)
756 + (width/2) * (pos_y/2) + pos_x/2;
757 /* In case height is odd, round up to even */
758 *uoff = *voff + (width/2) * ((height+1)/2);
760 case IPU_PIX_FMT_YVU422P:
761 *off = pos_y * width + pos_x;
762 *voff = (width * (height - pos_y) - pos_x)
763 + (width/2) * pos_y + pos_x/2;
764 *uoff = *voff + (width/2) * height;
766 case IPU_PIX_FMT_YUV422P:
767 *off = pos_y * width + pos_x;
768 *uoff = (width * (height - pos_y) - pos_x)
769 + (width/2) * pos_y + pos_x/2;
770 *voff = *uoff + (width/2) * height;
772 case IPU_PIX_FMT_YUV444P:
773 *off = pos_y * width + pos_x;
774 *uoff = width * height;
775 *voff = width * height * 2;
777 case IPU_PIX_FMT_NV12:
778 *off = pos_y * width + pos_x;
779 *uoff = (width * (height - pos_y) - pos_x)
780 + width * (pos_y/2) + pos_x;
782 case IPU_PIX_FMT_TILED_NV12:
784 * tiled format, progressive:
785 * assuming that line is aligned with MB height (aligned to 16)
786 * offset = line * stride + (pixel / MB_width) * pixels_in_MB
787 * = line * stride + (pixel / 16) * 256
788 * = line * stride + pixel * 16
790 *off = pos_y * width + (pos_x << 4);
791 *uoff = ALIGN(width * height, SZ_4K) + (*off >> 1) - *off;
793 case IPU_PIX_FMT_TILED_NV12F:
795 * tiled format, interlaced:
796 * same as above, only number of pixels in MB is 128,
799 *off = (pos_y >> 1) * width + (pos_x << 3);
800 *uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1) - *off;
803 *off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
806 *stride = width * bytes_per_pixel(fmt);
809 static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
811 struct stripe_param left_stripe;
812 struct stripe_param right_stripe;
813 struct stripe_param up_stripe;
814 struct stripe_param down_stripe;
819 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
820 return IPU_CHECK_ERR_SPLIT_WITH_ROT;
822 iw = t->input.crop.w;
823 ih = t->input.crop.h;
825 ow = t->output.crop.w;
826 oh = t->output.crop.h;
828 memset(&left_stripe, 0, sizeof(left_stripe));
829 memset(&right_stripe, 0, sizeof(right_stripe));
830 memset(&up_stripe, 0, sizeof(up_stripe));
831 memset(&down_stripe, 0, sizeof(down_stripe));
833 if (t->set.split_mode & RL_SPLIT) {
835 * We do want equal strips: initialize stripes in case
836 * calc_stripes returns before actually doing the calculation
838 left_stripe.input_width = iw / 2;
839 left_stripe.output_width = ow / 2;
840 right_stripe.input_column = iw / 2;
841 right_stripe.output_column = ow / 2;
844 max_width = soc_max_vdi_in_width();
846 max_width = soc_max_out_width();
847 ret = ipu_calc_stripes_sizes(iw,
850 (((unsigned long long)1) << 32), /* 32bit for fractional*/
851 1, /* equal stripes */
857 dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
859 t->set.sp_setting.iw = left_stripe.input_width;
860 t->set.sp_setting.ow = left_stripe.output_width;
861 t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
862 t->set.sp_setting.i_left_pos = left_stripe.input_column;
863 t->set.sp_setting.o_left_pos = left_stripe.output_column;
864 t->set.sp_setting.i_right_pos = right_stripe.input_column;
865 t->set.sp_setting.o_right_pos = right_stripe.output_column;
867 t->set.sp_setting.iw = iw;
868 t->set.sp_setting.ow = ow;
869 t->set.sp_setting.outh_resize_ratio = 0;
870 t->set.sp_setting.i_left_pos = 0;
871 t->set.sp_setting.o_left_pos = 0;
872 t->set.sp_setting.i_right_pos = 0;
873 t->set.sp_setting.o_right_pos = 0;
875 if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > iw)
876 return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
877 if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
878 || (t->set.sp_setting.ow > soc_max_out_width()))
879 return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
881 if (t->set.split_mode & UD_SPLIT) {
883 * We do want equal strips: initialize stripes in case
884 * calc_stripes returns before actually doing the calculation
886 up_stripe.input_width = ih / 2;
887 up_stripe.output_width = oh / 2;
888 down_stripe.input_column = ih / 2;
889 down_stripe.output_column = oh / 2;
890 ret = ipu_calc_stripes_sizes(ih,
892 soc_max_out_height(),
893 (((unsigned long long)1) << 32), /* 32bit for fractional*/
894 1, /* equal stripes */
900 dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
902 t->set.sp_setting.ih = up_stripe.input_width;
903 t->set.sp_setting.oh = up_stripe.output_width;
904 t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
905 t->set.sp_setting.i_top_pos = up_stripe.input_column;
906 t->set.sp_setting.o_top_pos = up_stripe.output_column;
907 t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
908 t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
910 t->set.sp_setting.ih = ih;
911 t->set.sp_setting.oh = oh;
912 t->set.sp_setting.outv_resize_ratio = 0;
913 t->set.sp_setting.i_top_pos = 0;
914 t->set.sp_setting.o_top_pos = 0;
915 t->set.sp_setting.i_bottom_pos = 0;
916 t->set.sp_setting.o_bottom_pos = 0;
918 if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > ih)
919 return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
920 if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
921 || (t->set.sp_setting.oh > soc_max_out_height()))
922 return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
927 static int check_task(struct ipu_task_entry *t)
930 int ret = IPU_CHECK_OK;
932 bool vdi_split = false;
934 if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
935 (IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
936 (IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
937 (IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
938 ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
939 !t->input.deinterlace.enable)) {
940 ret = IPU_CHECK_ERR_NOT_SUPPORT;
945 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
948 ret = IPU_CHECK_ERR_INPUT_CROP;
951 update_offset(t->input.format, t->input.width, t->input.height,
952 t->input.crop.pos.x, t->input.crop.pos.y,
953 &t->set.i_off, &t->set.i_uoff,
954 &t->set.i_voff, &t->set.istride);
957 ret = set_crop(&t->output.crop, t->output.width, t->output.height,
960 ret = IPU_CHECK_ERR_OUTPUT_CROP;
963 update_offset(t->output.format,
964 t->output.width, t->output.height,
965 t->output.crop.pos.x, t->output.crop.pos.y,
966 &t->set.o_off, &t->set.o_uoff,
967 &t->set.o_voff, &t->set.ostride);
969 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
970 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
971 if ((t->input.crop.w > soc_max_in_width(1)) ||
972 (t->input.crop.h > soc_max_in_height())) {
973 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
976 /* output fmt: NV12 and YUYV, now don't support resize */
977 if (((IPU_PIX_FMT_NV12 != t->output.format) &&
978 (IPU_PIX_FMT_YUYV != t->output.format)) ||
979 (t->input.crop.w != t->output.crop.w) ||
980 (t->input.crop.h != t->output.crop.h)) {
981 ret = IPU_CHECK_ERR_NOT_SUPPORT;
986 /* check overlay if there is */
988 if (t->input.deinterlace.enable) {
989 ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
993 ret = set_crop(&t->overlay.crop, t->overlay.width,
994 t->overlay.height, t->overlay.format);
996 ret = IPU_CHECK_ERR_OVERLAY_CROP;
999 int ow = t->output.crop.w;
1000 int oh = t->output.crop.h;
1002 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1003 ow = t->output.crop.h;
1004 oh = t->output.crop.w;
1006 if ((t->overlay.crop.w != ow) || (t->overlay.crop.h != oh)) {
1007 ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
1011 update_offset(t->overlay.format,
1012 t->overlay.width, t->overlay.height,
1013 t->overlay.crop.pos.x, t->overlay.crop.pos.y,
1014 &t->set.ov_off, &t->set.ov_uoff,
1015 &t->set.ov_voff, &t->set.ovstride);
1016 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
1017 t->set.ov_alpha_stride = t->overlay.width;
1018 t->set.ov_alpha_off = t->overlay.crop.pos.y *
1019 t->overlay.width + t->overlay.crop.pos.x;
1024 /* input overflow? */
1025 if (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1026 (IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
1027 if ((t->input.crop.w > soc_max_in_width(0)) ||
1028 (t->input.crop.h > soc_max_in_height())) {
1029 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
1034 /* check task mode */
1035 t->set.mode = NULL_MODE;
1036 t->set.split_mode = NO_SPLIT;
1038 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1040 tmp = t->output.crop.w;
1041 t->output.crop.w = t->output.crop.h;
1042 t->output.crop.h = tmp;
1045 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
1046 t->set.mode |= ROT_MODE;
1048 /*need resize or CSC?*/
1049 if ((t->input.crop.w != t->output.crop.w) ||
1050 (t->input.crop.h != t->output.crop.h) ||
1051 need_csc(t->input.format, t->output.format))
1052 t->set.mode |= IC_MODE;
1055 if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
1056 t->set.mode |= IC_MODE;
1058 /*need IDMAC do format(same color space)?*/
1059 if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
1060 t->set.mode |= IC_MODE;
1064 t->set.mode |= IC_MODE;
1067 if (t->input.deinterlace.enable) {
1068 t->set.mode &= ~IC_MODE;
1069 t->set.mode |= VDI_MODE;
1071 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1072 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1073 if (t->set.mode & ROT_MODE) {
1074 ret = IPU_CHECK_ERR_NOT_SUPPORT;
1077 t->set.mode |= VDOA_MODE;
1078 if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
1079 t->set.mode |= VDOA_BAND_MODE;
1080 t->set.mode &= ~IC_MODE;
1083 if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
1084 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
1085 if (t->output.crop.w > soc_max_out_width())
1086 t->set.split_mode |= RL_SPLIT;
1087 if (t->output.crop.h > soc_max_out_height())
1088 t->set.split_mode |= UD_SPLIT;
1089 if (!t->set.split_mode && (t->set.mode & VDI_MODE) &&
1090 (t->input.crop.w > soc_max_vdi_in_width())) {
1091 t->set.split_mode |= RL_SPLIT;
1094 if (t->set.split_mode) {
1095 if ((t->set.split_mode == RL_SPLIT) ||
1096 (t->set.split_mode == UD_SPLIT))
1097 timeout = DEF_TIMEOUT_MS * 2 + DEF_DELAY_MS;
1099 timeout = DEF_TIMEOUT_MS * 4 + DEF_DELAY_MS;
1100 if (t->timeout < timeout)
1101 t->timeout = timeout;
1103 ret = update_split_setting(t, vdi_split);
1104 if (ret > IPU_CHECK_ERR_MIN)
1109 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1111 tmp = t->output.crop.w;
1112 t->output.crop.w = t->output.crop.h;
1113 t->output.crop.h = tmp;
1116 if (t->set.mode == NULL_MODE) {
1117 ret = IPU_CHECK_ERR_PROC_NO_NEED;
1121 if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
1122 ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
1123 if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
1124 ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
1125 if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
1126 ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
1131 if (ret > IPU_CHECK_ERR_MIN)
1132 dump_check_err(t->dev, ret);
1133 else if (ret != IPU_CHECK_OK)
1134 dump_check_warn(t->dev, ret);
1140 static int prepare_task(struct ipu_task_entry *t)
1144 ret = check_task(t);
1145 if (ret > IPU_CHECK_ERR_MIN)
1148 if (t->set.mode & VDI_MODE) {
1149 if (t->task_id != IPU_TASK_ID_VF)
1150 t->task_id = IPU_TASK_ID_VF;
1151 t->set.task = VDI_VF;
1152 if (t->set.mode & ROT_MODE)
1153 t->set.task |= ROT_VF;
1156 if (VDOA_MODE == t->set.mode) {
1157 if (t->set.task != 0) {
1158 dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
1162 t->set.task |= VDOA_ONLY;
1165 if (VDOA_BAND_MODE & t->set.mode) {
1166 /* to save band size: 1<<3 = 8 lines */
1167 t->set.band_lines = 3;
1175 static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
1179 uint32_t status_rot;
1182 status = ipu_channel_status(ipu, MEM_VDI_PRP_VF_MEM);
1183 status_vf = ipu_channel_status(ipu, MEM_PRP_VF_MEM);
1184 status_rot = ipu_channel_status(ipu, MEM_ROT_VF_MEM);
1185 return status || status_vf || status_rot;
1187 status = ipu_channel_status(ipu, MEM_PP_MEM);
1188 status_rot = ipu_channel_status(ipu, MEM_ROT_PP_MEM);
1189 return status || status_rot;
1193 static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
1196 struct ipu_soc *ipu;
1198 uint32_t found_ipu = 0;
1199 uint32_t found_vdoa = 0;
1200 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1202 mutex_lock(&tbl->lock);
1203 if (t->set.mode & VDOA_MODE) {
1204 if (NULL != t->vdoa_handle)
1207 found_vdoa = tbl->vdoa_used ? 0 : 1;
1210 vdoa_get_handle(&t->vdoa_handle);
1212 /* first get vdoa->ipu resource sequence */
1214 if (t->set.task & VDOA_ONLY)
1219 for (i = 0; i < max_ipu_no; i++) {
1220 ipu = ipu_get_soc(i);
1222 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1223 t->task_no, found_vdoa, i);
1225 used = &tbl->used[i][IPU_PP_CH_VF];
1226 if (t->set.mode & VDI_MODE) {
1232 } else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1234 t->task_id = IPU_TASK_ID_VF;
1235 if (t->set.mode & IC_MODE)
1236 t->set.task |= IC_VF;
1237 if (t->set.mode & ROT_MODE)
1238 t->set.task |= ROT_VF;
1244 dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n",
1245 t->task_no, found_vdoa, t->set.mode);
1250 for (i = 0; i < max_ipu_no; i++) {
1251 ipu = ipu_get_soc(i);
1253 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1254 t->task_no, found_vdoa, i);
1256 if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1257 used = &tbl->used[i][IPU_PP_CH_PP];
1259 t->task_id = IPU_TASK_ID_PP;
1260 if (t->set.mode & IC_MODE)
1261 t->set.task |= IC_PP;
1262 if (t->set.mode & ROT_MODE)
1263 t->set.task |= ROT_PP;
1276 if (atomic_inc_return(&t->res_get) == 2)
1278 "ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
1279 t->task_no, found_vdoa);
1283 "%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
1284 __func__, t->task_no, found_vdoa, found_ipu);
1285 mutex_unlock(&tbl->lock);
1286 if (t->set.task & VDOA_ONLY)
1288 else if (t->set.mode & VDOA_MODE)
1289 return found_vdoa && found_ipu;
1294 static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
1297 int rel_vdoa = 0, rel_ipu = 0;
1298 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1300 mutex_lock(&tbl->lock);
1301 if (tsk->set.mode & VDOA_MODE) {
1302 if (!tbl->vdoa_used && tsk->vdoa_handle)
1304 "ERR no:0x%x,vdoa not used,mode:0x%x\n",
1305 tsk->task_no, tsk->set.mode);
1306 if (tbl->vdoa_used && tsk->vdoa_handle) {
1308 vdoa_put_handle(&tsk->vdoa_handle);
1310 tsk->ipu->vdoa_en = 0;
1312 if (vdoa_only || (tsk->set.task & VDOA_ONLY))
1317 tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
1319 ret = atomic_inc_return(&tsk->res_free);
1322 "ERR no:0x%x,rel_vdoa:%d,put ipu twice\n",
1323 tsk->task_no, rel_vdoa);
1326 "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
1327 __func__, tsk->task_no, rel_vdoa, rel_ipu);
1328 mutex_unlock(&tbl->lock);
1331 static int get_vdoa_ipu_res(struct ipu_task_entry *t)
1336 found = _get_vdoa_ipu_res(t);
1340 /* blocking to get resource */
1341 ret = atomic_inc_return(&req_cnt);
1343 "wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
1344 ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
1345 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
1347 dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
1348 t, t->task_no, t->timeout - DEF_DELAY_MS);
1350 t->state = STATE_RES_TIMEOUT;
1353 if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
1355 "ERR[no-0x%x] can not get ipu!\n",
1357 ret = atomic_read(&req_cnt);
1359 ret = atomic_dec_return(&req_cnt);
1362 "ERR[no-0x%x] req_cnt:%d mismatch!\n",
1364 dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n",
1365 t->task_no, t, ret);
1374 static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
1376 struct ipu_task_entry *tsk;
1378 tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
1380 return ERR_PTR(-ENOMEM);
1381 kref_init(&tsk->refcount);
1382 tsk->state = -EINVAL;
1385 tsk->input = task->input;
1386 tsk->output = task->output;
1387 tsk->overlay_en = task->overlay_en;
1388 if (tsk->overlay_en)
1389 tsk->overlay = task->overlay;
1390 if (tsk->timeout && (tsk->timeout > DEF_TIMEOUT_MS))
1391 tsk->timeout = task->timeout;
1393 tsk->timeout = DEF_TIMEOUT_MS;
1398 static void task_mem_free(struct kref *ref)
1400 struct ipu_task_entry *tsk =
1401 container_of(ref, struct ipu_task_entry, refcount);
1403 memset(tsk, 0, sizeof(*tsk));
1407 int create_split_child_task(struct ipu_split_task *sp_task)
1410 struct ipu_task_entry *tsk;
1412 tsk = create_task_entry(&sp_task->task);
1414 return PTR_ERR(tsk);
1416 sp_task->child_task = tsk;
1417 tsk->task_no = sp_task->task_no;
1419 ret = prepare_task(tsk);
1423 tsk->parent = sp_task->parent_task;
1424 tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
1426 list_add(&tsk->node, &tsk->parent->split_list);
1427 dev_dbg(tsk->dev, "[0x%p] sp_tsk Q list,no-0x%x\n", tsk, tsk->task_no);
1428 tsk->state = STATE_QUEUE;
1429 CHECK_PERF(&tsk->ts_queue);
1434 static inline int sp_task_check_done(struct ipu_split_task *sp_task,
1435 struct ipu_task_entry *parent, int num, int *idx)
1439 struct ipu_task_entry *tsk;
1440 struct mutex *lock = &parent->split_lock;
1444 for (i = 0; i < num; i++) {
1445 tsk = sp_task[i].child_task;
1446 if (tsk && tsk->split_done) {
1458 static int create_split_task(
1460 struct ipu_split_task *sp_task)
1462 struct ipu_task *task = &(sp_task->task);
1463 struct ipu_task_entry *t = sp_task->parent_task;
1466 sp_task->task_no |= stripe;
1468 task->input = t->input;
1469 task->output = t->output;
1470 task->overlay_en = t->overlay_en;
1471 if (task->overlay_en)
1472 task->overlay = t->overlay;
1473 task->task_id = t->task_id;
1474 if ((t->set.split_mode == RL_SPLIT) ||
1475 (t->set.split_mode == UD_SPLIT))
1476 task->timeout = t->timeout / 2;
1478 task->timeout = t->timeout / 4;
1480 task->input.crop.w = t->set.sp_setting.iw;
1481 task->input.crop.h = t->set.sp_setting.ih;
1482 if (task->overlay_en) {
1483 task->overlay.crop.w = t->set.sp_setting.ow;
1484 task->overlay.crop.h = t->set.sp_setting.oh;
1486 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1487 task->output.crop.w = t->set.sp_setting.oh;
1488 task->output.crop.h = t->set.sp_setting.ow;
1489 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos;
1490 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos;
1493 task->output.crop.w = t->set.sp_setting.ow;
1494 task->output.crop.h = t->set.sp_setting.oh;
1495 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos;
1496 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos;
1499 if (stripe & LEFT_STRIPE)
1500 task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
1501 else if (stripe & RIGHT_STRIPE)
1502 task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
1503 if (stripe & UP_STRIPE)
1504 task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
1505 else if (stripe & DOWN_STRIPE)
1506 task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
1508 if (task->overlay_en) {
1509 if (stripe & LEFT_STRIPE)
1510 task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
1511 else if (stripe & RIGHT_STRIPE)
1512 task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
1513 if (stripe & UP_STRIPE)
1514 task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
1515 else if (stripe & DOWN_STRIPE)
1516 task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1519 switch (t->output.rotate) {
1520 case IPU_ROTATE_NONE:
1521 if (stripe & LEFT_STRIPE)
1522 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1523 else if (stripe & RIGHT_STRIPE)
1524 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1525 if (stripe & UP_STRIPE)
1526 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1527 else if (stripe & DOWN_STRIPE)
1528 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1530 case IPU_ROTATE_VERT_FLIP:
1531 if (stripe & LEFT_STRIPE)
1532 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1533 else if (stripe & RIGHT_STRIPE)
1534 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1535 if (stripe & UP_STRIPE)
1536 task->output.crop.pos.y =
1537 t->output.crop.pos.y + t->output.crop.h
1538 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1539 else if (stripe & DOWN_STRIPE)
1540 task->output.crop.pos.y =
1541 t->output.crop.pos.y + t->output.crop.h
1542 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1544 case IPU_ROTATE_HORIZ_FLIP:
1545 if (stripe & LEFT_STRIPE)
1546 task->output.crop.pos.x =
1547 t->output.crop.pos.x + t->output.crop.w
1548 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1549 else if (stripe & RIGHT_STRIPE)
1550 task->output.crop.pos.x =
1551 t->output.crop.pos.x + t->output.crop.w
1552 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1553 if (stripe & UP_STRIPE)
1554 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1555 else if (stripe & DOWN_STRIPE)
1556 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1558 case IPU_ROTATE_180:
1559 if (stripe & LEFT_STRIPE)
1560 task->output.crop.pos.x =
1561 t->output.crop.pos.x + t->output.crop.w
1562 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1563 else if (stripe & RIGHT_STRIPE)
1564 task->output.crop.pos.x =
1565 t->output.crop.pos.x + t->output.crop.w
1566 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1567 if (stripe & UP_STRIPE)
1568 task->output.crop.pos.y =
1569 t->output.crop.pos.y + t->output.crop.h
1570 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1571 else if (stripe & DOWN_STRIPE)
1572 task->output.crop.pos.y =
1573 t->output.crop.pos.y + t->output.crop.h
1574 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1576 case IPU_ROTATE_90_RIGHT:
1577 if (stripe & UP_STRIPE)
1578 task->output.crop.pos.x =
1579 t->output.crop.pos.x + t->output.crop.w
1580 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1581 else if (stripe & DOWN_STRIPE)
1582 task->output.crop.pos.x =
1583 t->output.crop.pos.x + t->output.crop.w
1584 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1585 if (stripe & LEFT_STRIPE)
1586 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1587 else if (stripe & RIGHT_STRIPE)
1588 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1590 case IPU_ROTATE_90_RIGHT_HFLIP:
1591 if (stripe & UP_STRIPE)
1592 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1593 else if (stripe & DOWN_STRIPE)
1594 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1595 if (stripe & LEFT_STRIPE)
1596 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1597 else if (stripe & RIGHT_STRIPE)
1598 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1600 case IPU_ROTATE_90_RIGHT_VFLIP:
1601 if (stripe & UP_STRIPE)
1602 task->output.crop.pos.x =
1603 t->output.crop.pos.x + t->output.crop.w
1604 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1605 else if (stripe & DOWN_STRIPE)
1606 task->output.crop.pos.x =
1607 t->output.crop.pos.x + t->output.crop.w
1608 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1609 if (stripe & LEFT_STRIPE)
1610 task->output.crop.pos.y =
1611 t->output.crop.pos.y + t->output.crop.h
1612 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1613 else if (stripe & RIGHT_STRIPE)
1614 task->output.crop.pos.y =
1615 t->output.crop.pos.y + t->output.crop.h
1616 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1618 case IPU_ROTATE_90_LEFT:
1619 if (stripe & UP_STRIPE)
1620 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1621 else if (stripe & DOWN_STRIPE)
1622 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1623 if (stripe & LEFT_STRIPE)
1624 task->output.crop.pos.y =
1625 t->output.crop.pos.y + t->output.crop.h
1626 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1627 else if (stripe & RIGHT_STRIPE)
1628 task->output.crop.pos.y =
1629 t->output.crop.pos.y + t->output.crop.h
1630 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1633 dev_err(t->dev, "ERR:should not be here\n");
1637 ret = create_split_child_task(sp_task);
1639 dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
1643 static int queue_split_task(struct ipu_task_entry *t,
1644 struct ipu_split_task *sp_task, uint32_t size)
1649 struct ipu_task_entry *tsk = NULL;
1650 struct mutex *lock = &t->split_lock;
1652 dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
1653 t, t->task_no, size);
1655 init_waitqueue_head(&t->split_waitq);
1656 INIT_LIST_HEAD(&t->split_list);
1657 for (j = 0; j < size; j++) {
1658 memset(&sp_task[j], 0, sizeof(*sp_task));
1659 sp_task[j].parent_task = t;
1660 sp_task[j].task_no = t->task_no;
1663 if (t->set.split_mode == RL_SPLIT) {
1665 err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
1669 err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
1670 } else if (t->set.split_mode == UD_SPLIT) {
1672 err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
1676 err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
1679 err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1683 err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1687 err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
1691 err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
1695 for (j = 0; j < (i + 1); j++) {
1697 if (sp_task[j].child_task)
1699 "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
1700 j, sp_task[j].child_task->task_no,
1701 sp_task[j].child_task->state, err[j]);
1704 dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
1705 sp_task[j].child_task, j, sp_task[j].child_task->task_no,
1706 state_msg[sp_task[j].child_task->state].msg, err[j]);
1712 for (j = 0; j < (i + 1); j++) {
1713 if (err[j] < 0 && !ret)
1715 tsk = sp_task[j].child_task;
1719 memset(tsk, 0, sizeof(*tsk));
1721 t->state = STATE_ERR;
1726 static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
1727 ipu_channel_t channel, uint32_t ch_type)
1732 dma_addr_t inbuf_base = 0;
1734 struct vdoa_params param;
1735 struct vdoa_ipu_buf buf;
1736 struct ipu_soc *ipu_idx;
1737 u32 ipu_stride, obuf_size;
1741 if ((IPU_PIX_FMT_YUYV != t->output.format) &&
1742 (IPU_PIX_FMT_NV12 != t->output.format)) {
1743 dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
1747 memset(¶m, 0, sizeof(param));
1748 /* init channel tiled bufs */
1749 if (deinterlace_3_field(t) &&
1750 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1751 field_size = tiled_filed_size(t);
1752 if (INPUT_CHAN_VDI_P == ch_type) {
1753 inbuf_base = t->input.paddr + field_size;
1754 param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
1755 } else if (INPUT_CHAN == ch_type) {
1756 inbuf_base = t->input.paddr_n;
1757 param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
1758 } else if (INPUT_CHAN_VDI_N == ch_type) {
1759 inbuf_base = t->input.paddr_n + field_size;
1760 param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
1763 height = t->input.crop.h >> 1; /* field format for vdoa */
1764 width = t->input.crop.w;
1765 param.vfield_buf.vubo = t->set.i_uoff;
1766 param.interlaced = 1;
1767 param.scan_order = 1;
1768 type = IPU_INPUT_BUFFER;
1769 } else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
1770 (INPUT_CHAN == ch_type)) {
1771 height = t->input.crop.h;
1772 width = t->input.crop.w;
1773 param.vframe_buf.veba = t->input.paddr + t->set.i_off;
1774 param.vframe_buf.vubo = t->set.i_uoff;
1775 type = IPU_INPUT_BUFFER;
1779 param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
1780 if (param.band_mode && (t->set.band_lines != 3) &&
1781 (t->set.band_lines != 4) && (t->set.band_lines != 5))
1783 else if (param.band_mode)
1784 param.band_lines = (1 << t->set.band_lines);
1785 for (i = 0; i < max_ipu_no; i++) {
1786 ipu_idx = ipu_get_soc(i);
1787 if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
1790 if (t->set.task & VDOA_ONLY)
1791 /* dummy, didn't need ipu res */
1793 if (max_ipu_no == i) {
1794 dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
1799 param.vpu_stride = t->input.width;
1800 param.height = height;
1801 param.width = width;
1802 if (IPU_PIX_FMT_NV12 == t->output.format)
1803 param.pfs = VDOA_PFS_NV12;
1805 param.pfs = VDOA_PFS_YUYV;
1806 ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
1808 ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
1809 obuf_size = PAGE_ALIGN(param.width * param.height *
1810 fmt_to_bpp(ipu_fmt)/8);
1811 dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
1812 param.band_mode, param.band_lines);
1813 if (!param.band_mode) {
1814 /* note: if only for tiled -> raster convert and
1815 no other post-processing, we don't need alloc buf
1816 and use output buffer directly.
1818 if (t->set.task & VDOA_ONLY)
1819 param.ieba0 = t->output.paddr;
1821 dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
1825 if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
1826 dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
1830 ret = vdoa_setup(t->vdoa_handle, ¶m);
1833 vdoa_get_output_buf(t->vdoa_handle, &buf);
1834 if (t->set.task & VDOA_ONLY)
1837 ret = ipu_init_channel_buffer(ipu,
1851 t->state = STATE_INIT_CHAN_BUF_FAIL;
1855 if (param.band_mode) {
1856 ret = ipu_set_channel_bandmode(ipu, channel,
1857 type, t->set.band_lines);
1859 t->state = STATE_INIT_CHAN_BAND_FAIL;
1867 static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
1871 if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
1872 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1873 CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
1874 } else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
1875 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1876 CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
1877 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
1879 CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
1880 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
1882 CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
1885 dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n",
1886 t->task_no, t->input.format);
1893 static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
1896 ipu_channel_params_t params;
1897 dma_addr_t inbuf = 0, ovbuf = 0, ov_alp_buf = 0;
1898 dma_addr_t inbuf_p = 0, inbuf_n = 0;
1899 dma_addr_t outbuf = 0;
1900 int out_uoff = 0, out_voff = 0, out_rot;
1901 int out_w = 0, out_h = 0, out_stride;
1903 u32 vdi_frame_idx = 0;
1905 memset(¶ms, 0, sizeof(params));
1907 /* is it need link a rot channel */
1908 if (ic_and_rot(t->set.mode)) {
1909 outbuf = t->set.r_paddr;
1910 out_w = t->set.r_width;
1911 out_h = t->set.r_height;
1912 out_stride = t->set.r_stride;
1913 out_fmt = t->set.r_fmt;
1916 out_rot = IPU_ROTATE_NONE;
1918 outbuf = t->output.paddr + t->set.o_off;
1919 out_w = t->output.crop.w;
1920 out_h = t->output.crop.h;
1921 out_stride = t->set.ostride;
1922 out_fmt = t->output.format;
1923 out_uoff = t->set.o_uoff;
1924 out_voff = t->set.o_voff;
1925 out_rot = t->output.rotate;
1929 params.mem_prp_vf_mem.in_width = t->input.crop.w;
1930 params.mem_prp_vf_mem.out_width = out_w;
1931 params.mem_prp_vf_mem.in_height = t->input.crop.h;
1932 params.mem_prp_vf_mem.out_height = out_h;
1933 params.mem_prp_vf_mem.in_pixel_fmt = t->input.format;
1934 params.mem_prp_vf_mem.out_pixel_fmt = out_fmt;
1935 params.mem_prp_vf_mem.motion_sel = t->input.deinterlace.motion;
1937 params.mem_prp_vf_mem.outh_resize_ratio =
1938 t->set.sp_setting.outh_resize_ratio;
1939 params.mem_prp_vf_mem.outv_resize_ratio =
1940 t->set.sp_setting.outv_resize_ratio;
1942 if (t->overlay_en) {
1943 params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
1944 params.mem_prp_vf_mem.graphics_combine_en = 1;
1945 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
1946 params.mem_prp_vf_mem.global_alpha_en = 1;
1947 else if (t->overlay.alpha.loc_alp_paddr)
1948 params.mem_prp_vf_mem.alpha_chan_en = 1;
1949 /* otherwise, alpha bending per pixel is used. */
1950 params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
1951 if (t->overlay.colorkey.enable) {
1952 params.mem_prp_vf_mem.key_color_en = 1;
1953 params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
1957 if (t->input.deinterlace.enable) {
1958 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_FIELD_MASK)
1959 params.mem_prp_vf_mem.field_fmt =
1960 IPU_DEINTERLACE_FIELD_BOTTOM;
1962 params.mem_prp_vf_mem.field_fmt =
1963 IPU_DEINTERLACE_FIELD_TOP;
1965 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
1966 vdi_frame_idx = t->input.deinterlace.field_fmt &
1967 IPU_DEINTERLACE_RATE_FRAME1;
1970 if (t->set.mode & VDOA_MODE)
1974 if (!(t->set.task & VDOA_ONLY)) {
1975 ret = ipu_init_channel(ipu, t->set.ic_chan, ¶ms);
1977 t->state = STATE_INIT_CHAN_FAIL;
1982 if (deinterlace_3_field(t)) {
1983 ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, ¶ms);
1985 t->state = STATE_INIT_CHAN_FAIL;
1988 ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, ¶ms);
1990 t->state = STATE_INIT_CHAN_FAIL;
1995 /* init channel bufs */
1996 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1997 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1998 ret = init_tiled_ch_bufs(ipu, t);
2002 if ((deinterlace_3_field(t)) &&
2003 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2004 if (params.mem_prp_vf_mem.field_fmt ==
2005 IPU_DEINTERLACE_FIELD_TOP) {
2006 if (vdi_frame_idx) {
2007 inbuf_p = t->input.paddr + t->set.istride +
2009 inbuf = t->input.paddr_n + t->set.i_off;
2010 inbuf_n = t->input.paddr_n + t->set.istride +
2012 params.mem_prp_vf_mem.field_fmt =
2013 IPU_DEINTERLACE_FIELD_BOTTOM;
2015 inbuf_p = t->input.paddr + t->set.i_off;
2016 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2017 inbuf_n = t->input.paddr_n + t->set.i_off;
2020 if (vdi_frame_idx) {
2021 inbuf_p = t->input.paddr + t->set.i_off;
2022 inbuf = t->input.paddr_n + t->set.istride + t->set.i_off;
2023 inbuf_n = t->input.paddr_n + t->set.i_off;
2024 params.mem_prp_vf_mem.field_fmt =
2025 IPU_DEINTERLACE_FIELD_TOP;
2027 inbuf_p = t->input.paddr + t->set.istride +
2029 inbuf = t->input.paddr + t->set.i_off;
2030 inbuf_n = t->input.paddr_n + t->set.istride +
2035 if (t->input.deinterlace.enable) {
2036 if (params.mem_prp_vf_mem.field_fmt ==
2037 IPU_DEINTERLACE_FIELD_TOP) {
2038 if (vdi_frame_idx) {
2039 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2040 params.mem_prp_vf_mem.field_fmt =
2041 IPU_DEINTERLACE_FIELD_BOTTOM;
2043 inbuf = t->input.paddr + t->set.i_off;
2045 if (vdi_frame_idx) {
2046 inbuf = t->input.paddr + t->set.i_off;
2047 params.mem_prp_vf_mem.field_fmt =
2048 IPU_DEINTERLACE_FIELD_TOP;
2050 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2053 inbuf = t->input.paddr + t->set.i_off;
2057 ovbuf = t->overlay.paddr + t->set.ov_off;
2059 if (t->overlay_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
2060 ov_alp_buf = t->overlay.alpha.loc_alp_paddr
2061 + t->set.ov_alpha_off;
2063 if ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
2064 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2065 ret = ipu_init_channel_buffer(ipu,
2079 t->state = STATE_INIT_CHAN_BUF_FAIL;
2083 if (deinterlace_3_field(t) &&
2084 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2085 ret = ipu_init_channel_buffer(ipu,
2086 t->set.vdi_ic_p_chan,
2099 t->state = STATE_INIT_CHAN_BUF_FAIL;
2103 ret = ipu_init_channel_buffer(ipu,
2104 t->set.vdi_ic_n_chan,
2117 t->state = STATE_INIT_CHAN_BUF_FAIL;
2122 if (t->overlay_en) {
2123 ret = ipu_init_channel_buffer(ipu,
2125 IPU_GRAPH_IN_BUFFER,
2137 t->state = STATE_INIT_CHAN_BUF_FAIL;
2142 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2143 ret = ipu_init_channel_buffer(ipu,
2145 IPU_ALPHA_IN_BUFFER,
2146 IPU_PIX_FMT_GENERIC,
2149 t->set.ov_alpha_stride,
2156 t->state = STATE_INIT_CHAN_BUF_FAIL;
2161 if (!(t->set.task & VDOA_ONLY)) {
2162 ret = ipu_init_channel_buffer(ipu,
2176 t->state = STATE_INIT_CHAN_BUF_FAIL;
2181 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2182 ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2183 CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
2184 STATE_LINK_CHAN_FAIL, done, ret);
2191 static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
2195 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2196 ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2197 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
2198 STATE_UNLINK_CHAN_FAIL, ret);
2200 ipu_uninit_channel(ipu, t->set.ic_chan);
2201 if (deinterlace_3_field(t)) {
2202 ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
2203 ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
2207 static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2210 dma_addr_t inbuf = 0, outbuf = 0;
2211 int in_uoff = 0, in_voff = 0;
2212 int in_fmt, in_width, in_height, in_stride;
2215 ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
2217 t->state = STATE_INIT_CHAN_FAIL;
2221 /* init channel buf */
2222 /* is it need link to a ic channel */
2223 if (ic_and_rot(t->set.mode)) {
2224 in_fmt = t->set.r_fmt;
2225 in_width = t->set.r_width;
2226 in_height = t->set.r_height;
2227 in_stride = t->set.r_stride;
2228 inbuf = t->set.r_paddr;
2232 in_fmt = t->input.format;
2233 in_width = t->input.crop.w;
2234 in_height = t->input.crop.h;
2235 in_stride = t->set.istride;
2236 inbuf = t->input.paddr + t->set.i_off;
2237 in_uoff = t->set.i_uoff;
2238 in_voff = t->set.i_voff;
2240 outbuf = t->output.paddr + t->set.o_off;
2242 ret = ipu_init_channel_buffer(ipu,
2256 t->state = STATE_INIT_CHAN_BUF_FAIL;
2260 ret = ipu_init_channel_buffer(ipu,
2274 t->state = STATE_INIT_CHAN_BUF_FAIL;
2282 static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2284 ipu_uninit_channel(ipu, t->set.rot_chan);
2287 static int get_irq(struct ipu_task_entry *t)
2292 if (only_ic(t->set.mode))
2293 chan = t->set.ic_chan;
2295 chan = t->set.rot_chan;
2298 case MEM_ROT_VF_MEM:
2299 irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
2301 case MEM_ROT_PP_MEM:
2302 irq = IPU_IRQ_PP_ROT_OUT_EOF;
2304 case MEM_VDI_PRP_VF_MEM:
2305 case MEM_PRP_VF_MEM:
2306 irq = IPU_IRQ_PRP_VF_OUT_EOF;
2309 irq = IPU_IRQ_PP_OUT_EOF;
2312 irq = IPU_IRQ_VDIC_OUT_EOF;
2321 static irqreturn_t task_irq_handler(int irq, void *dev_id)
2323 struct ipu_task_entry *prev_tsk = dev_id;
2325 CHECK_PERF(&prev_tsk->ts_inirq);
2326 complete(&prev_tsk->irq_comp);
2327 dev_dbg(prev_tsk->dev, "[0x%p] no-0x%x in-irq!",
2328 prev_tsk, prev_tsk->task_no);
2333 /* Fix deinterlace up&down split mode medium line */
2334 static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
2341 unsigned char *base_off;
2342 struct ipu_task_entry *parent = t->parent;
2345 dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
2348 stripe_mode = t->task_no & 0xf;
2349 task_no = t->task_no >> 4;
2351 base_off = (char *) __va(t->output.paddr);
2352 if (base_off == NULL) {
2353 dev_err(t->dev, "ERR[0x%p]Falied get vitual address\n", t);
2357 vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
2358 vdi_size = vdi_save_lines * t->output.crop.w * 2;
2360 if (vdi_save_lines <= 0) {
2361 dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
2365 /*check vditmpbuf buffer have alloced or buffer size is changed */
2366 if ((vdi_save_lines != parent->old_save_lines) ||
2367 (vdi_size != parent->old_size)) {
2368 if (parent->vditmpbuf[0] != NULL)
2369 kfree(parent->vditmpbuf[0]);
2370 if (parent->vditmpbuf[1] != NULL)
2371 kfree(parent->vditmpbuf[1]);
2373 parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
2374 if (parent->vditmpbuf[0] == NULL) {
2376 "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
2379 memset(parent->vditmpbuf[0], 0, vdi_size);
2381 parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
2382 if (parent->vditmpbuf[1] == NULL) {
2384 "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
2387 memset(parent->vditmpbuf[1], 0, vdi_size);
2389 parent->old_save_lines = vdi_save_lines;
2390 parent->old_size = vdi_size;
2393 /* UP stripe or UP&LEFT stripe */
2394 if ((stripe_mode == UP_STRIPE) ||
2395 (stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
2396 if (!parent->buf0filled) {
2397 offset_addr = t->set.o_off +
2398 t->set.sp_setting.ud_split_line*t->set.ostride;
2399 dmac_flush_range(base_off + offset_addr,
2400 base_off + offset_addr + vdi_size);
2401 outer_flush_range(t->output.paddr + offset_addr,
2402 t->output.paddr + offset_addr + vdi_size);
2404 for (i = 0; i < vdi_save_lines; i++)
2405 memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
2406 base_off + offset_addr +
2407 i*t->set.ostride, t->output.crop.w*2);
2408 parent->buf0filled = true;
2410 offset_addr = t->set.o_off + (t->output.crop.h -
2411 vdi_save_lines) * t->set.ostride;
2412 for (i = 0; i < vdi_save_lines; i++)
2413 memcpy(base_off + offset_addr + i*t->set.ostride,
2414 parent->vditmpbuf[0] + i*t->output.crop.w*2,
2415 t->output.crop.w*2);
2417 dmac_flush_range(base_off + offset_addr,
2418 base_off + offset_addr + i*t->set.ostride);
2419 outer_flush_range(t->output.paddr + offset_addr,
2420 t->output.paddr + offset_addr + i*t->set.ostride);
2421 parent->buf0filled = false;
2424 /*Down stripe or Down&Left stripe*/
2425 else if ((stripe_mode == DOWN_STRIPE) ||
2426 (stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
2427 if (!parent->buf0filled) {
2428 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2429 dmac_flush_range(base_off + offset_addr,
2430 base_off + offset_addr + vdi_size);
2431 outer_flush_range(t->output.paddr + offset_addr,
2432 t->output.paddr + offset_addr + vdi_size);
2434 for (i = 0; i < vdi_save_lines; i++)
2435 memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
2436 base_off + offset_addr + i*t->set.ostride,
2437 t->output.crop.w*2);
2438 parent->buf0filled = true;
2440 offset_addr = t->set.o_off;
2441 for (i = 0; i < vdi_save_lines; i++)
2442 memcpy(base_off + offset_addr + i*t->set.ostride,
2443 parent->vditmpbuf[0] + i*t->output.crop.w*2,
2444 t->output.crop.w*2);
2446 dmac_flush_range(base_off + offset_addr,
2447 base_off + offset_addr + i*t->set.ostride);
2448 outer_flush_range(t->output.paddr + offset_addr,
2449 t->output.paddr + offset_addr + i*t->set.ostride);
2450 parent->buf0filled = false;
2454 else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
2455 if (!parent->buf1filled) {
2456 offset_addr = t->set.o_off +
2457 t->set.sp_setting.ud_split_line*t->set.ostride;
2458 dmac_flush_range(base_off + offset_addr,
2459 base_off + offset_addr + vdi_size);
2460 outer_flush_range(t->output.paddr + offset_addr,
2461 t->output.paddr + offset_addr + vdi_size);
2463 for (i = 0; i < vdi_save_lines; i++)
2464 memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
2465 base_off + offset_addr + i*t->set.ostride,
2466 t->output.crop.w*2);
2467 parent->buf1filled = true;
2469 offset_addr = t->set.o_off +
2470 (t->output.crop.h - vdi_save_lines)*t->set.ostride;
2471 for (i = 0; i < vdi_save_lines; i++)
2472 memcpy(base_off + offset_addr + i*t->set.ostride,
2473 parent->vditmpbuf[1] + i*t->output.crop.w*2,
2474 t->output.crop.w*2);
2476 dmac_flush_range(base_off + offset_addr,
2477 base_off + offset_addr + i*t->set.ostride);
2478 outer_flush_range(t->output.paddr + offset_addr,
2479 t->output.paddr + offset_addr + i*t->set.ostride);
2480 parent->buf1filled = false;
2483 /*Down stripe or Down&Right stript*/
2484 else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
2485 if (!parent->buf1filled) {
2486 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2487 dmac_flush_range(base_off + offset_addr,
2488 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2489 outer_flush_range(t->output.paddr + offset_addr,
2490 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2492 for (i = 0; i < vdi_save_lines; i++)
2493 memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
2494 base_off + offset_addr + i*t->set.ostride,
2495 t->output.crop.w*2);
2496 parent->buf1filled = true;
2498 offset_addr = t->set.o_off;
2499 for (i = 0; i < vdi_save_lines; i++)
2500 memcpy(base_off + offset_addr + i*t->set.ostride,
2501 parent->vditmpbuf[1] + i*t->output.crop.w*2,
2502 t->output.crop.w*2);
2504 dmac_flush_range(base_off + offset_addr,
2505 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2506 outer_flush_range(t->output.paddr + offset_addr,
2507 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2508 parent->buf1filled = false;
2513 static void do_task_release(struct ipu_task_entry *t, int fail)
2516 struct ipu_soc *ipu = t->ipu;
2518 if (t->input.deinterlace.enable && !fail &&
2519 (t->task_no & (UP_STRIPE | DOWN_STRIPE)))
2520 vdi_split_process(ipu, t);
2522 ipu_free_irq(ipu, t->irq, t);
2524 if (t->vdoa_dma.vaddr)
2525 dma_free_coherent(t->dev,
2530 if (only_ic(t->set.mode)) {
2531 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2532 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
2533 STATE_DISABLE_CHAN_FAIL, ret);
2534 if (deinterlace_3_field(t)) {
2535 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2537 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_p",
2538 STATE_DISABLE_CHAN_FAIL, ret);
2539 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2541 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_n",
2542 STATE_DISABLE_CHAN_FAIL, ret);
2544 } else if (only_rot(t->set.mode)) {
2545 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2546 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_rot",
2547 STATE_DISABLE_CHAN_FAIL, ret);
2548 } else if (ic_and_rot(t->set.mode)) {
2549 ret = ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan);
2550 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch",
2551 STATE_UNLINK_CHAN_FAIL, ret);
2552 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2553 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-rot",
2554 STATE_DISABLE_CHAN_FAIL, ret);
2555 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2556 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-ic",
2557 STATE_DISABLE_CHAN_FAIL, ret);
2558 if (deinterlace_3_field(t)) {
2559 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2561 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-p",
2562 STATE_DISABLE_CHAN_FAIL, ret);
2563 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2565 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-n",
2566 STATE_DISABLE_CHAN_FAIL, ret);
2570 if (only_ic(t->set.mode))
2572 else if (only_rot(t->set.mode))
2574 else if (ic_and_rot(t->set.mode)) {
2579 t->state = STATE_OK;
2580 CHECK_PERF(&t->ts_rel);
2584 static void do_task_vdoa_only(struct ipu_task_entry *t)
2588 ret = init_tiled_ch_bufs(NULL, t);
2589 CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
2590 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2591 vdoa_stop(t->vdoa_handle);
2592 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
2593 STATE_VDOA_IRQ_TIMEOUT, out, ret);
2595 t->state = STATE_OK;
2600 static void do_task(struct ipu_task_entry *t)
2606 struct ipu_soc *ipu = t->ipu;
2608 CHECK_PERF(&t->ts_dotask);
2611 t->state = STATE_NO_IPU;
2615 init_completion(&t->irq_comp);
2616 dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
2617 t->task_no, t->task_id);
2620 if (t->set.task & IC_PP) {
2621 t->set.ic_chan = MEM_PP_MEM;
2622 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
2623 } else if (t->set.task & IC_VF) {
2624 t->set.ic_chan = MEM_PRP_VF_MEM;
2625 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
2626 } else if (t->set.task & VDI_VF) {
2627 if (t->set.mode & VDOA_BAND_MODE) {
2628 t->set.ic_chan = MEM_VDI_MEM;
2629 if (deinterlace_3_field(t)) {
2630 t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
2631 t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
2633 dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
2636 t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
2637 if (deinterlace_3_field(t)) {
2638 t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
2639 t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
2642 "[0x%p]ic ch MEM_VDI_PRP_VF_MEM\n", t);
2646 if (t->set.task & ROT_PP) {
2647 t->set.rot_chan = MEM_ROT_PP_MEM;
2648 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
2649 } else if (t->set.task & ROT_VF) {
2650 t->set.rot_chan = MEM_ROT_VF_MEM;
2651 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
2654 if (t->task_id == IPU_TASK_ID_VF)
2655 busy = ic_vf_pp_is_busy(ipu, true);
2656 else if (t->task_id == IPU_TASK_ID_PP)
2657 busy = ic_vf_pp_is_busy(ipu, false);
2659 dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n",
2660 t->task_no, t->task_id);
2664 dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n",
2665 (void *)t, t->task_no, t->task_id);
2666 t->state = STATE_IPU_BUSY;
2672 t->state = STATE_NO_IRQ;
2678 if (only_ic(t->set.mode)) {
2679 dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
2680 ret = init_ic(ipu, t);
2681 CHECK_RETCODE(ret < 0, "init_ic only_ic",
2682 t->state, chan_setup, ret);
2683 } else if (only_rot(t->set.mode)) {
2684 dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
2685 ret = init_rot(ipu, t);
2686 CHECK_RETCODE(ret < 0, "init_rot only_rot",
2687 t->state, chan_setup, ret);
2688 } else if (ic_and_rot(t->set.mode)) {
2689 int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1;
2691 dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
2692 t->set.r_fmt = t->output.format;
2693 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
2694 t->set.r_width = t->output.crop.h;
2695 t->set.r_height = t->output.crop.w;
2697 t->set.r_width = t->output.crop.w;
2698 t->set.r_height = t->output.crop.h;
2700 t->set.r_stride = t->set.r_width *
2701 bytes_per_pixel(t->set.r_fmt);
2702 r_size = PAGE_ALIGN(t->set.r_width * t->set.r_height
2703 * fmt_to_bpp(t->set.r_fmt)/8);
2705 if (r_size > ipu->rot_dma[rot_idx].size) {
2706 dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t);
2708 if (ipu->rot_dma[rot_idx].vaddr)
2709 dma_free_coherent(t->dev,
2710 ipu->rot_dma[rot_idx].size,
2711 ipu->rot_dma[rot_idx].vaddr,
2712 ipu->rot_dma[rot_idx].paddr);
2714 ipu->rot_dma[rot_idx].size = r_size;
2715 ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev,
2717 &ipu->rot_dma[rot_idx].paddr,
2718 GFP_DMA | GFP_KERNEL);
2719 CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
2720 "ic_and_rot", STATE_SYS_NO_MEM,
2721 chan_setup, -ENOMEM);
2723 t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
2725 dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
2726 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
2727 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
2728 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
2729 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
2730 dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
2732 ret = init_ic(ipu, t);
2733 CHECK_RETCODE(ret < 0, "init_ic ic_and_rot",
2734 t->state, chan_setup, ret);
2735 ret = init_rot(ipu, t);
2736 CHECK_RETCODE(ret < 0, "init_rot ic_and_rot",
2737 t->state, chan_setup, ret);
2738 ret = ipu_link_channels(ipu, t->set.ic_chan,
2740 CHECK_RETCODE(ret < 0, "ipu_link_ch ic_and_rot",
2741 STATE_LINK_CHAN_FAIL, chan_setup, ret);
2743 dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t);
2744 t->state = STATE_ERR;
2748 ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, t);
2749 CHECK_RETCODE(ret < 0, "ipu_req_irq",
2750 STATE_IRQ_FAIL, chan_setup, ret);
2752 /* enable/start channel */
2753 if (only_ic(t->set.mode)) {
2754 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2755 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic",
2756 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2757 if (deinterlace_3_field(t)) {
2758 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2759 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_p",
2760 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2761 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2762 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_n",
2763 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2766 ret = ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER,
2768 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic",
2769 STATE_SEL_BUF_FAIL, chan_buf, ret);
2770 if (t->overlay_en) {
2771 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2772 IPU_GRAPH_IN_BUFFER, 0);
2773 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_g",
2774 STATE_SEL_BUF_FAIL, chan_buf, ret);
2775 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2776 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2777 IPU_ALPHA_IN_BUFFER, 0);
2778 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_a",
2779 STATE_SEL_BUF_FAIL, chan_buf,
2783 if (!(t->set.mode & VDOA_BAND_MODE)) {
2784 if (deinterlace_3_field(t))
2785 ipu_select_multi_vdi_buffer(ipu, 0);
2787 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2788 IPU_INPUT_BUFFER, 0);
2789 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
2790 STATE_SEL_BUF_FAIL, chan_buf, ret);
2793 } else if (only_rot(t->set.mode)) {
2794 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2795 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_rot",
2796 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2797 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2798 IPU_OUTPUT_BUFFER, 0);
2799 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_o",
2800 STATE_SEL_BUF_FAIL, chan_buf, ret);
2801 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2802 IPU_INPUT_BUFFER, 0);
2803 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_i",
2804 STATE_SEL_BUF_FAIL, chan_buf, ret);
2805 } else if (ic_and_rot(t->set.mode)) {
2806 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2807 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-rot",
2808 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2809 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2810 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-ic",
2811 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2812 if (deinterlace_3_field(t)) {
2813 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2814 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-p",
2815 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2816 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2817 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-n",
2818 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2821 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2822 IPU_OUTPUT_BUFFER, 0);
2823 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-rot-o",
2824 STATE_SEL_BUF_FAIL, chan_buf, ret);
2825 if (t->overlay_en) {
2826 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2827 IPU_GRAPH_IN_BUFFER, 0);
2828 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-g",
2829 STATE_SEL_BUF_FAIL, chan_buf, ret);
2830 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2831 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2832 IPU_ALPHA_IN_BUFFER, 0);
2833 CHECK_RETCODE(ret < 0, "ipu_sel_buf icrot-ic-a",
2838 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2839 IPU_OUTPUT_BUFFER, 0);
2840 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-o",
2841 STATE_SEL_BUF_FAIL, chan_buf, ret);
2842 if (deinterlace_3_field(t))
2843 ipu_select_multi_vdi_buffer(ipu, 0);
2845 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2846 IPU_INPUT_BUFFER, 0);
2847 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-i",
2848 STATE_SEL_BUF_FAIL, chan_buf, ret);
2853 t->state = STATE_IN_PROGRESS;
2855 if (t->set.mode & VDOA_BAND_MODE) {
2856 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2857 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
2858 STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
2861 CHECK_PERF(&t->ts_waitirq);
2862 ret = wait_for_completion_timeout(&t->irq_comp,
2863 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
2864 CHECK_PERF(&t->ts_wakeup);
2865 CHECK_RETCODE(ret == 0, "wait_for_comp_timeout",
2866 STATE_IRQ_TIMEOUT, chan_rel, ret);
2867 dev_dbg(t->dev, "[0x%p] no-0x%x ipu irq done!", t, t->task_no);
2873 if (t->set.mode & VDOA_BAND_MODE)
2874 vdoa_stop(t->vdoa_handle);
2875 do_task_release(t, t->state >= STATE_ERR);
2879 static void do_task_vdoa_vdi(struct ipu_task_entry *t)
2885 /* FIXME: crop mode not support now */
2886 stripe_width = t->input.width >> 1;
2887 t->input.crop.pos.x = 0;
2888 t->input.crop.pos.y = 0;
2889 t->input.crop.w = stripe_width;
2890 t->input.crop.h = t->input.height;
2891 t->output.crop.w = stripe_width;
2892 t->output.crop.h = t->input.height;
2894 for (i = 0; i < 2; i++) {
2895 t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
2896 t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
2898 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
2904 update_offset(t->input.format,
2905 t->input.width, t->input.height,
2906 t->input.crop.pos.x,
2907 t->input.crop.pos.y,
2908 &t->set.i_off, &t->set.i_uoff,
2909 &t->set.i_voff, &t->set.istride);
2910 dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
2911 t->set.i_off, t->set.i_uoff, t->set.istride);
2913 ret = set_crop(&t->output.crop, t->input.width,
2914 t->output.height, t->output.format);
2919 update_offset(t->output.format,
2920 t->output.width, t->output.height,
2921 t->output.crop.pos.x,
2922 t->output.crop.pos.y,
2923 &t->set.o_off, &t->set.o_uoff,
2924 &t->set.o_voff, &t->set.ostride);
2926 dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
2927 t->set.o_off, t->set.o_uoff, t->set.ostride);
2934 dev_err(t->dev, "ERR %s set_crop.\n", __func__);
2939 static void get_res_do_task(struct ipu_task_entry *t)
2942 uint32_t split_child;
2945 found = get_vdoa_ipu_res(t);
2947 dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n",
2951 if (t->set.task & VDOA_ONLY)
2952 do_task_vdoa_only(t);
2953 else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
2954 (t->set.mode & VDOA_BAND_MODE) &&
2955 (t->input.crop.w > soc_max_vdi_in_width()))
2956 do_task_vdoa_vdi(t);
2959 put_vdoa_ipu_res(t, 0);
2961 if (t->state != STATE_OK) {
2962 dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
2963 t, t->task_no, state_msg[t->state].msg);
2966 split_child = need_split(t) && t->parent;
2968 lock = &t->parent->split_lock;
2972 wake_up(&t->parent->split_waitq);
2978 static void wait_split_task_complete(struct ipu_task_entry *parent,
2979 struct ipu_split_task *sp_task, uint32_t size)
2981 struct ipu_task_entry *tsk = NULL;
2984 unsigned long flags;
2985 struct mutex *lock = &parent->split_lock;
2986 int k, busy_vf, busy_pp;
2987 struct ipu_soc *ipu;
2990 for (j = 0; j < size; j++) {
2991 rc = wait_event_timeout(
2992 parent->split_waitq,
2993 sp_task_check_done(sp_task, parent, size, &idx),
2994 msecs_to_jiffies(parent->timeout - DEF_DELAY_MS));
2996 dev_err(parent->dev,
2997 "ERR:[0x%p] no-0x%x, split_task timeout,j:%d,"
2999 parent, parent->task_no, j, size);
3004 dev_err(parent->dev,
3005 "ERR:[0x%p] no-0x%x, invalid task idx:%d\n",
3006 parent, parent->task_no, idx);
3009 tsk = sp_task[idx].child_task;
3011 if (!tsk->split_done || !tsk->ipu)
3013 "ERR:no-0x%x,split not done:%d/null ipu:0x%p\n",
3014 tsk->task_no, tsk->split_done, tsk->ipu);
3015 tsk->split_done = 0;
3019 "[0x%p] no-0x%x sp_tsk[%d] done,state:%d.\n",
3020 tsk, tsk->task_no, idx, tsk->state);
3022 CHECK_PERF(&tsk->ts_rel);
3023 PRINT_TASK_STATISTICS;
3029 if (ret == -ETIMEDOUT) {
3031 for (k = 0; k < max_ipu_no; k++) {
3032 ipu = ipu_get_soc(k);
3034 dev_err(parent->dev, "no:0x%x, null ipu:%d\n",
3035 parent->task_no, k);
3037 busy_vf = ic_vf_pp_is_busy(ipu, true);
3038 busy_pp = ic_vf_pp_is_busy(ipu, false);
3039 dev_err(parent->dev,
3040 "ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
3041 k, busy_vf, busy_pp);
3044 for (k = 0; k < size; k++) {
3045 tsk = sp_task[k].child_task;
3048 dev_err(parent->dev,
3049 "ERR: sp_task[%d][0x%p] no-0x%x done:%d,"
3050 "state:%s,on_list:%d, ipu:0x%p,timeout!\n",
3051 k, tsk, tsk->task_no, tsk->split_done,
3052 state_msg[tsk->state].msg, tsk->task_in_list,
3057 for (j = 0; j < size; j++) {
3058 tsk = sp_task[j].child_task;
3061 spin_lock_irqsave(&ipu_task_list_lock, flags);
3062 if (tsk->task_in_list) {
3063 list_del(&tsk->node);
3064 tsk->task_in_list = 0;
3066 "[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
3067 tsk, tsk->task_no, tsk->task_id);
3069 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3072 if (tsk->state != STATE_OK) {
3074 "ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n",
3075 tsk, tsk->task_no, tsk->task_id,
3076 state_msg[tsk->state].msg);
3078 kref_put(&tsk->refcount, task_mem_free);
3081 kfree(parent->vditmpbuf[0]);
3082 kfree(parent->vditmpbuf[1]);
3085 parent->state = STATE_TIMEOUT;
3087 parent->state = STATE_OK;
3091 static inline int find_task(struct ipu_task_entry **t, int thread_id)
3094 unsigned long flags;
3095 struct ipu_task_entry *tsk;
3096 struct list_head *task_list = &ipu_task_list;
3099 spin_lock_irqsave(&ipu_task_list_lock, flags);
3100 found = !list_empty(task_list);
3102 tsk = list_first_entry(task_list, struct ipu_task_entry, node);
3103 if (tsk->task_in_list) {
3104 list_del(&tsk->node);
3105 tsk->task_in_list = 0;
3107 kref_get(&tsk->refcount);
3109 "thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n",
3110 thread_id, tsk, tsk->task_no, tsk->set.mode);
3113 "thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n",
3114 thread_id, tsk->task_no, tsk->set.mode);
3116 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3121 static int ipu_task_thread(void *argv)
3123 struct ipu_task_entry *tsk;
3124 struct ipu_task_entry *sp_tsk0;
3125 struct ipu_split_task sp_task[4];
3126 /* priority lower than irq_thread */
3127 const struct sched_param param = {
3128 .sched_priority = MAX_USER_RT_PRIO/2 - 1,
3133 unsigned long flags;
3135 struct cpumask cpu_mask;
3136 struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
3139 curr_thread_id = thread_id;
3140 sched_setscheduler(current, SCHED_FIFO, ¶m);
3142 if (!data->is_vdoa) {
3143 cpu = cpumask_first(cpu_online_mask);
3144 cpumask_set_cpu(cpu, &cpu_mask);
3145 ret = sched_setaffinity(data->ipu->thread[data->id]->pid,
3148 pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret);
3150 pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu);
3153 while (!kthread_should_stop()) {
3158 wait_event(thread_waitq, find_task(&tsk, curr_thread_id));
3161 pr_err("thread:%d can not find task.\n",
3166 /* note: other threads run split child task */
3167 split_parent = need_split(tsk) && !tsk->parent;
3168 split_child = need_split(tsk) && tsk->parent;
3170 if ((tsk->set.split_mode == RL_SPLIT) ||
3171 (tsk->set.split_mode == UD_SPLIT))
3175 ret = queue_split_task(tsk, sp_task, size);
3179 struct list_head *pos;
3181 spin_lock_irqsave(&ipu_task_list_lock, flags);
3183 sp_tsk0 = list_first_entry(&tsk->split_list,
3184 struct ipu_task_entry, node);
3185 list_del(&sp_tsk0->node);
3187 list_for_each(pos, &tsk->split_list) {
3188 struct ipu_task_entry *tmp;
3190 tmp = list_entry(pos,
3191 struct ipu_task_entry, node);
3192 tmp->task_in_list = 1;
3194 "[0x%p] no-0x%x,id:%d sp_tsk "
3195 "add_to_list.\n", tmp,
3196 tmp->task_no, tmp->task_id);
3198 /* add to global list */
3199 list_splice(&tsk->split_list, &ipu_task_list);
3201 spin_unlock_irqrestore(&ipu_task_list_lock,
3203 /* let the parent thread do the first sp_task */
3204 /* FIXME: ensure the correct sequence for split
3208 "ERR: no-0x%x,can not get split_tsk0\n",
3210 wake_up(&thread_waitq);
3211 get_res_do_task(sp_tsk0);
3212 dev_dbg(sp_tsk0->dev,
3213 "thread:%d complete tsk no:0x%x.\n",
3214 curr_thread_id, sp_tsk0->task_no);
3215 ret = atomic_read(&req_cnt);
3217 wake_up(&res_waitq);
3218 dev_dbg(sp_tsk0->dev,
3219 "sp_tsk0 sche thread:%d no:0x%x,"
3220 "req_cnt:%d\n", curr_thread_id,
3221 sp_tsk0->task_no, ret);
3222 /* For other threads to get_res */
3227 get_res_do_task(tsk);
3229 /* wait for all 4 sp_task finished here or timeout
3230 and then release all resources */
3231 if (split_parent && !split_fail)
3232 wait_split_task_complete(tsk, sp_task, size);
3235 atomic_inc(&tsk->done);
3236 wake_up(&tsk->task_waitq);
3239 dev_dbg(tsk->dev, "thread:%d complete tsk no:0x%x-[0x%p].\n",
3240 curr_thread_id, tsk->task_no, tsk);
3241 ret = atomic_read(&req_cnt);
3243 wake_up(&res_waitq);
3244 dev_dbg(tsk->dev, "sche thread:%d no:0x%x,req_cnt:%d\n",
3245 curr_thread_id, tsk->task_no, ret);
3246 /* note: give cpu to other threads to get_res */
3250 kref_put(&tsk->refcount, task_mem_free);
3253 pr_info("ERR %s exit.\n", __func__);
3257 int ipu_check_task(struct ipu_task *task)
3259 struct ipu_task_entry *tsk;
3262 tsk = create_task_entry(task);
3264 return PTR_ERR(tsk);
3266 ret = check_task(tsk);
3268 task->input = tsk->input;
3269 task->output = tsk->output;
3270 task->overlay = tsk->overlay;
3271 dump_task_info(tsk);
3273 kref_put(&tsk->refcount, task_mem_free);
3275 pr_debug("%s ret:%d.\n", __func__, ret);
3278 EXPORT_SYMBOL_GPL(ipu_check_task);
3280 int ipu_queue_task(struct ipu_task *task)
3282 struct ipu_task_entry *tsk;
3283 unsigned long flags;
3288 tsk = create_task_entry(task);
3290 return PTR_ERR(tsk);
3292 CHECK_PERF(&tsk->ts_queue);
3293 ret = prepare_task(tsk);
3297 if (need_split(tsk)) {
3298 CHECK_PERF(&tsk->ts_dotask);
3299 CHECK_PERF(&tsk->ts_waitirq);
3300 CHECK_PERF(&tsk->ts_inirq);
3301 CHECK_PERF(&tsk->ts_wakeup);
3304 /* task_no last four bits for split task type*/
3305 tmp_task_no = atomic_inc_return(&frame_no);
3306 tsk->task_no = tmp_task_no << 4;
3307 init_waitqueue_head(&tsk->task_waitq);
3309 spin_lock_irqsave(&ipu_task_list_lock, flags);
3310 list_add_tail(&tsk->node, &ipu_task_list);
3311 tsk->task_in_list = 1;
3312 dev_dbg(tsk->dev, "[0x%p,no-0x%x] list_add_tail\n", tsk, tsk->task_no);
3313 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3314 wake_up(&thread_waitq);
3316 ret = wait_event_timeout(tsk->task_waitq, atomic_read(&tsk->done),
3317 msecs_to_jiffies(tsk->timeout));
3319 /* note: the timeout should larger than the internal timeout!*/
3321 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x, timeout:%dms!\n",
3322 tsk, tsk->task_no, tsk->timeout);
3324 if (STATE_OK != tsk->state) {
3325 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x,state %d: %s\n",
3326 tsk, tsk->task_no, tsk->state,
3327 state_msg[tsk->state].msg);
3333 spin_lock_irqsave(&ipu_task_list_lock, flags);
3334 if (tsk->task_in_list) {
3335 list_del(&tsk->node);
3336 tsk->task_in_list = 0;
3337 dev_dbg(tsk->dev, "[0x%p] no:0x%x list_del\n",
3340 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3343 CHECK_PERF(&tsk->ts_rel);
3344 PRINT_TASK_STATISTICS;
3345 if (ts_frame_avg == 0)
3346 ts_frame_avg = ts_frame.tv_nsec / NSEC_PER_USEC +
3347 ts_frame.tv_sec * USEC_PER_SEC;
3349 ts_frame_avg = (ts_frame_avg + ts_frame.tv_nsec / NSEC_PER_USEC
3350 + ts_frame.tv_sec * USEC_PER_SEC)/2;
3351 if (timespec_compare(&ts_frame, &ts_frame_max) > 0)
3352 ts_frame_max = ts_frame;
3354 atomic_inc(&frame_cnt);
3356 if ((atomic_read(&frame_cnt) % 1000) == 0)
3357 pr_debug("ipu_dev: max frame time:%ldus, avg frame time:%dus,"
3358 "frame_cnt:%d\n", ts_frame_max.tv_nsec / NSEC_PER_USEC
3359 + ts_frame_max.tv_sec * USEC_PER_SEC,
3360 ts_frame_avg, atomic_read(&frame_cnt));
3364 dev_err(tsk->dev, "ERR: no-0x%x,ipu_queue_task err:%d\n",
3367 kref_put(&tsk->refcount, task_mem_free);
3371 EXPORT_SYMBOL_GPL(ipu_queue_task);
3373 static int mxc_ipu_open(struct inode *inode, struct file *file)
3375 file->private_data = (void *)atomic_inc_return(&file_index);
3379 static long mxc_ipu_ioctl(struct file *file,
3380 unsigned int cmd, unsigned long arg)
3382 int __user *argp = (void __user *)arg;
3386 case IPU_CHECK_TASK:
3388 struct ipu_task task;
3391 (&task, (struct ipu_task *) arg,
3392 sizeof(struct ipu_task)))
3394 ret = ipu_check_task(&task);
3395 if (copy_to_user((struct ipu_task *) arg,
3396 &task, sizeof(struct ipu_task)))
3400 case IPU_QUEUE_TASK:
3402 struct ipu_task task;
3405 (&task, (struct ipu_task *) arg,
3406 sizeof(struct ipu_task)))
3408 ret = ipu_queue_task(&task);
3414 struct ipu_alloc_list *mem;
3416 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
3420 if (get_user(size, argp))
3423 mem->size = PAGE_ALIGN(size);
3425 mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
3427 GFP_DMA | GFP_KERNEL);
3428 if (mem->cpu_addr == NULL) {
3432 mem->file_index = file->private_data;
3433 mutex_lock(&ipu_alloc_lock);
3434 list_add(&mem->list, &ipu_alloc_list);
3435 mutex_unlock(&ipu_alloc_lock);
3437 dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
3438 mem->size, mem->phy_addr);
3440 if (put_user(mem->phy_addr, argp))
3447 unsigned long offset;
3448 struct ipu_alloc_list *mem;
3450 if (get_user(offset, argp))
3454 mutex_lock(&ipu_alloc_lock);
3455 list_for_each_entry(mem, &ipu_alloc_list, list) {
3456 if (mem->phy_addr == offset) {
3457 list_del(&mem->list);
3458 dma_free_coherent(ipu_dev,
3467 mutex_unlock(&ipu_alloc_lock);
3469 dev_dbg(ipu_dev, "free %d bytes @ 0x%08X\n",
3470 mem->size, mem->phy_addr);
3480 static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
3484 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
3485 struct ipu_alloc_list *mem;
3487 mutex_lock(&ipu_alloc_lock);
3488 list_for_each_entry(mem, &ipu_alloc_list, list) {
3489 if (offset == mem->phy_addr) {
3495 mutex_unlock(&ipu_alloc_lock);
3499 if (vma->vm_end - vma->vm_start > len)
3502 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
3504 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
3505 vma->vm_end - vma->vm_start,
3506 vma->vm_page_prot)) {
3514 static int mxc_ipu_release(struct inode *inode, struct file *file)
3516 struct ipu_alloc_list *mem;
3517 struct ipu_alloc_list *n;
3519 mutex_lock(&ipu_alloc_lock);
3520 list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
3521 if ((mem->cpu_addr != 0) &&
3522 (file->private_data == mem->file_index)) {
3523 list_del(&mem->list);
3524 dma_free_coherent(ipu_dev,
3528 dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
3529 mem->size, mem->phy_addr);
3533 mutex_unlock(&ipu_alloc_lock);
3534 atomic_dec(&file_index);
3539 static struct file_operations mxc_ipu_fops = {
3540 .owner = THIS_MODULE,
3541 .open = mxc_ipu_open,
3542 .mmap = mxc_ipu_mmap,
3543 .release = mxc_ipu_release,
3544 .unlocked_ioctl = mxc_ipu_ioctl,
3547 int register_ipu_device(struct ipu_soc *ipu, int id)
3551 static struct ipu_thread_data thread_data[5];
3554 major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
3556 printk(KERN_ERR "Unable to register mxc_ipu as a char device\n");
3558 goto register_cdev_fail;
3561 ipu_class = class_create(THIS_MODULE, "mxc_ipu");
3562 if (IS_ERR(ipu_class)) {
3563 ret = PTR_ERR(ipu_class);
3564 goto ipu_class_fail;
3567 ipu_dev = device_create(ipu_class, NULL, MKDEV(major, 0),
3569 if (IS_ERR(ipu_dev)) {
3570 ret = PTR_ERR(ipu_dev);
3571 goto dev_create_fail;
3573 ipu_dev->dma_mask = kmalloc(sizeof(*ipu_dev->dma_mask), GFP_KERNEL);
3574 *ipu_dev->dma_mask = DMA_BIT_MASK(32);
3575 ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32);
3577 mutex_init(&ipu_ch_tbl.lock);
3580 ipu->rot_dma[0].size = 0;
3581 ipu->rot_dma[1].size = 0;
3583 thread_data[idx].ipu = ipu;
3584 thread_data[idx].id = 0;
3585 thread_data[idx].is_vdoa = 0;
3586 ipu->thread[0] = kthread_run(ipu_task_thread, &thread_data[idx++],
3588 if (IS_ERR(ipu->thread[0])) {
3589 ret = PTR_ERR(ipu->thread[0]);
3593 thread_data[idx].ipu = ipu;
3594 thread_data[idx].id = 1;
3595 thread_data[idx].is_vdoa = 0;
3596 ipu->thread[1] = kthread_run(ipu_task_thread, &thread_data[idx++],
3598 if (IS_ERR(ipu->thread[1])) {
3599 ret = PTR_ERR(ipu->thread[1]);
3607 kthread_stop(ipu->thread[0]);
3610 device_destroy(ipu_class, MKDEV(major, 0));
3613 class_destroy(ipu_class);
3617 unregister_chrdev(major, "mxc_ipu");
3622 void unregister_ipu_device(struct ipu_soc *ipu, int id)
3626 kthread_stop(ipu->thread[0]);
3627 kthread_stop(ipu->thread[1]);
3628 for (i = 0; i < 2; i++) {
3629 if (ipu->rot_dma[i].vaddr)
3630 dma_free_coherent(ipu_dev,
3631 ipu->rot_dma[i].size,
3632 ipu->rot_dma[i].vaddr,
3633 ipu->rot_dma[i].paddr);
3637 device_destroy(ipu_class, MKDEV(major, 0));
3638 class_destroy(ipu_class);
3639 unregister_chrdev(major, "mxc_ipu");