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 + 16))
723 || ((crop->h + crop->pos.y) > height + 16)) {
724 pr_err("set_crop error exceeds width/height.\n");
733 crop->w -= crop->w%8;
734 crop->h -= crop->h%8;
737 if ((crop->w == 0) || (crop->h == 0)) {
738 pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
746 static void update_offset(unsigned int fmt,
747 unsigned int width, unsigned int height,
748 unsigned int pos_x, unsigned int pos_y,
749 int *off, int *uoff, int *voff, int *stride)
751 /* NOTE: u v offset should based on start point of off*/
753 case IPU_PIX_FMT_YUV420P2:
754 case IPU_PIX_FMT_YUV420P:
755 *off = pos_y * width + pos_x;
756 *uoff = (width * (height - pos_y) - pos_x)
757 + (width/2) * (pos_y/2) + pos_x/2;
758 /* In case height is odd, round up to even */
759 *voff = *uoff + (width/2) * ((height+1)/2);
761 case IPU_PIX_FMT_YVU420P:
762 *off = pos_y * width + pos_x;
763 *voff = (width * (height - pos_y) - pos_x)
764 + (width/2) * (pos_y/2) + pos_x/2;
765 /* In case height is odd, round up to even */
766 *uoff = *voff + (width/2) * ((height+1)/2);
768 case IPU_PIX_FMT_YVU422P:
769 *off = pos_y * width + pos_x;
770 *voff = (width * (height - pos_y) - pos_x)
771 + (width/2) * pos_y + pos_x/2;
772 *uoff = *voff + (width/2) * height;
774 case IPU_PIX_FMT_YUV422P:
775 *off = pos_y * width + pos_x;
776 *uoff = (width * (height - pos_y) - pos_x)
777 + (width/2) * pos_y + pos_x/2;
778 *voff = *uoff + (width/2) * height;
780 case IPU_PIX_FMT_YUV444P:
781 *off = pos_y * width + pos_x;
782 *uoff = width * height;
783 *voff = width * height * 2;
785 case IPU_PIX_FMT_NV12:
786 *off = pos_y * width + pos_x;
787 *uoff = (width * (height - pos_y) - pos_x)
788 + width * (pos_y/2) + pos_x;
790 case IPU_PIX_FMT_TILED_NV12:
792 * tiled format, progressive:
793 * assuming that line is aligned with MB height (aligned to 16)
794 * offset = line * stride + (pixel / MB_width) * pixels_in_MB
795 * = line * stride + (pixel / 16) * 256
796 * = line * stride + pixel * 16
798 *off = pos_y * width + (pos_x << 4);
799 *uoff = ALIGN(width * height, SZ_4K) + (*off >> 1) - *off;
801 case IPU_PIX_FMT_TILED_NV12F:
803 * tiled format, interlaced:
804 * same as above, only number of pixels in MB is 128,
807 *off = (pos_y >> 1) * width + (pos_x << 3);
808 *uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1) - *off;
811 *off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
814 *stride = width * bytes_per_pixel(fmt);
817 static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
819 struct stripe_param left_stripe;
820 struct stripe_param right_stripe;
821 struct stripe_param up_stripe;
822 struct stripe_param down_stripe;
827 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
828 return IPU_CHECK_ERR_SPLIT_WITH_ROT;
830 iw = t->input.crop.w;
831 ih = t->input.crop.h;
833 ow = t->output.crop.w;
834 oh = t->output.crop.h;
836 memset(&left_stripe, 0, sizeof(left_stripe));
837 memset(&right_stripe, 0, sizeof(right_stripe));
838 memset(&up_stripe, 0, sizeof(up_stripe));
839 memset(&down_stripe, 0, sizeof(down_stripe));
841 if (t->set.split_mode & RL_SPLIT) {
843 * We do want equal strips: initialize stripes in case
844 * calc_stripes returns before actually doing the calculation
846 left_stripe.input_width = iw / 2;
847 left_stripe.output_width = ow / 2;
848 right_stripe.input_column = iw / 2;
849 right_stripe.output_column = ow / 2;
852 max_width = soc_max_vdi_in_width();
854 max_width = soc_max_out_width();
855 ret = ipu_calc_stripes_sizes(iw,
858 (((unsigned long long)1) << 32), /* 32bit for fractional*/
859 1, /* equal stripes */
865 return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
867 dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
869 t->set.sp_setting.iw = left_stripe.input_width;
870 t->set.sp_setting.ow = left_stripe.output_width;
871 t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
872 t->set.sp_setting.i_left_pos = left_stripe.input_column;
873 t->set.sp_setting.o_left_pos = left_stripe.output_column;
874 t->set.sp_setting.i_right_pos = right_stripe.input_column;
875 t->set.sp_setting.o_right_pos = right_stripe.output_column;
877 t->set.sp_setting.iw = iw;
878 t->set.sp_setting.ow = ow;
879 t->set.sp_setting.outh_resize_ratio = 0;
880 t->set.sp_setting.i_left_pos = 0;
881 t->set.sp_setting.o_left_pos = 0;
882 t->set.sp_setting.i_right_pos = 0;
883 t->set.sp_setting.o_right_pos = 0;
885 if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > (iw+16))
886 return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
887 if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
888 || (t->set.sp_setting.ow > soc_max_out_width()))
889 return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
891 if (t->set.split_mode & UD_SPLIT) {
893 * We do want equal strips: initialize stripes in case
894 * calc_stripes returns before actually doing the calculation
896 up_stripe.input_width = ih / 2;
897 up_stripe.output_width = oh / 2;
898 down_stripe.input_column = ih / 2;
899 down_stripe.output_column = oh / 2;
900 ret = ipu_calc_stripes_sizes(ih,
902 soc_max_out_height(),
903 (((unsigned long long)1) << 32), /* 32bit for fractional*/
904 0x1 | 0x2, /* equal stripes and vertical */
910 return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
912 dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
914 t->set.sp_setting.ih = up_stripe.input_width;
915 t->set.sp_setting.oh = up_stripe.output_width;
916 t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
917 t->set.sp_setting.i_top_pos = up_stripe.input_column;
918 t->set.sp_setting.o_top_pos = up_stripe.output_column;
919 t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
920 t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
922 t->set.sp_setting.ih = ih;
923 t->set.sp_setting.oh = oh;
924 t->set.sp_setting.outv_resize_ratio = 0;
925 t->set.sp_setting.i_top_pos = 0;
926 t->set.sp_setting.o_top_pos = 0;
927 t->set.sp_setting.i_bottom_pos = 0;
928 t->set.sp_setting.o_bottom_pos = 0;
931 if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > (ih+16))
932 return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
933 if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
934 || (t->set.sp_setting.oh > soc_max_out_height()))
935 return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
940 static int check_task(struct ipu_task_entry *t)
943 int ret = IPU_CHECK_OK;
945 bool vdi_split = false;
948 if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
949 (IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
950 (IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
951 (IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
952 ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
953 !t->input.deinterlace.enable)) {
954 ret = IPU_CHECK_ERR_NOT_SUPPORT;
959 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
962 ret = IPU_CHECK_ERR_INPUT_CROP;
965 update_offset(t->input.format, t->input.width, t->input.height,
966 t->input.crop.pos.x, t->input.crop.pos.y,
967 &t->set.i_off, &t->set.i_uoff,
968 &t->set.i_voff, &t->set.istride);
971 ret = set_crop(&t->output.crop, t->output.width, t->output.height,
974 ret = IPU_CHECK_ERR_OUTPUT_CROP;
977 update_offset(t->output.format,
978 t->output.width, t->output.height,
979 t->output.crop.pos.x, t->output.crop.pos.y,
980 &t->set.o_off, &t->set.o_uoff,
981 &t->set.o_voff, &t->set.ostride);
983 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
985 * Cache output width and height and
986 * swap them so that we may check
987 * downsize overflow correctly.
989 ocw = t->output.crop.h;
990 och = t->output.crop.w;
992 ocw = t->output.crop.w;
993 och = t->output.crop.h;
996 if (ocw * 8 <= t->input.crop.w) {
997 ret = IPU_CHECK_ERR_W_DOWNSIZE_OVER;
1001 if (och * 8 <= t->input.crop.h) {
1002 ret = IPU_CHECK_ERR_H_DOWNSIZE_OVER;
1006 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1007 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1008 if ((t->input.crop.w > soc_max_in_width(1)) ||
1009 (t->input.crop.h > soc_max_in_height())) {
1010 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
1013 /* output fmt: NV12 and YUYV, now don't support resize */
1014 if (((IPU_PIX_FMT_NV12 != t->output.format) &&
1015 (IPU_PIX_FMT_YUYV != t->output.format)) ||
1016 (t->input.crop.w != t->output.crop.w) ||
1017 (t->input.crop.h != t->output.crop.h)) {
1018 ret = IPU_CHECK_ERR_NOT_SUPPORT;
1023 /* check overlay if there is */
1024 if (t->overlay_en) {
1025 if (t->input.deinterlace.enable) {
1026 ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
1030 ret = set_crop(&t->overlay.crop, t->overlay.width,
1031 t->overlay.height, t->overlay.format);
1033 ret = IPU_CHECK_ERR_OVERLAY_CROP;
1036 ocw = t->output.crop.w;
1037 och = t->output.crop.h;
1039 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1040 ocw = t->output.crop.h;
1041 och = t->output.crop.w;
1043 if ((t->overlay.crop.w != ocw) ||
1044 (t->overlay.crop.h != och)) {
1045 ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
1049 update_offset(t->overlay.format,
1050 t->overlay.width, t->overlay.height,
1051 t->overlay.crop.pos.x, t->overlay.crop.pos.y,
1052 &t->set.ov_off, &t->set.ov_uoff,
1053 &t->set.ov_voff, &t->set.ovstride);
1054 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
1055 t->set.ov_alpha_stride = t->overlay.width;
1056 t->set.ov_alpha_off = t->overlay.crop.pos.y *
1057 t->overlay.width + t->overlay.crop.pos.x;
1062 /* input overflow? */
1063 if (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1064 (IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
1065 if ((t->input.crop.w > soc_max_in_width(0)) ||
1066 (t->input.crop.h > soc_max_in_height())) {
1067 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
1072 /* check task mode */
1073 t->set.mode = NULL_MODE;
1074 t->set.split_mode = NO_SPLIT;
1076 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1078 tmp = t->output.crop.w;
1079 t->output.crop.w = t->output.crop.h;
1080 t->output.crop.h = tmp;
1083 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
1084 t->set.mode |= ROT_MODE;
1086 /*need resize or CSC?*/
1087 if ((t->input.crop.w != t->output.crop.w) ||
1088 (t->input.crop.h != t->output.crop.h) ||
1089 need_csc(t->input.format, t->output.format))
1090 t->set.mode |= IC_MODE;
1093 if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
1094 t->set.mode |= IC_MODE;
1096 /*need IDMAC do format(same color space)?*/
1097 if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
1098 t->set.mode |= IC_MODE;
1102 t->set.mode |= IC_MODE;
1105 if (t->input.deinterlace.enable) {
1106 t->set.mode &= ~IC_MODE;
1107 t->set.mode |= VDI_MODE;
1109 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1110 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1111 if (t->set.mode & ROT_MODE) {
1112 ret = IPU_CHECK_ERR_NOT_SUPPORT;
1115 t->set.mode |= VDOA_MODE;
1116 if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
1117 t->set.mode |= VDOA_BAND_MODE;
1118 t->set.mode &= ~IC_MODE;
1121 if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
1122 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
1123 if (t->output.crop.w > soc_max_out_width())
1124 t->set.split_mode |= RL_SPLIT;
1125 if (t->output.crop.h > soc_max_out_height())
1126 t->set.split_mode |= UD_SPLIT;
1127 if (!t->set.split_mode && (t->set.mode & VDI_MODE) &&
1128 (t->input.crop.w > soc_max_vdi_in_width())) {
1129 t->set.split_mode |= RL_SPLIT;
1132 if (t->set.split_mode) {
1133 if ((t->set.split_mode == RL_SPLIT) ||
1134 (t->set.split_mode == UD_SPLIT))
1135 timeout = DEF_TIMEOUT_MS * 2 + DEF_DELAY_MS;
1137 timeout = DEF_TIMEOUT_MS * 4 + DEF_DELAY_MS;
1138 if (t->timeout < timeout)
1139 t->timeout = timeout;
1141 ret = update_split_setting(t, vdi_split);
1142 if (ret > IPU_CHECK_ERR_MIN)
1147 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1149 tmp = t->output.crop.w;
1150 t->output.crop.w = t->output.crop.h;
1151 t->output.crop.h = tmp;
1154 if (t->set.mode == NULL_MODE) {
1155 ret = IPU_CHECK_ERR_PROC_NO_NEED;
1159 if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
1160 ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
1161 if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
1162 ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
1163 if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
1164 ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
1169 if (ret > IPU_CHECK_ERR_MIN)
1170 dump_check_err(t->dev, ret);
1171 else if (ret != IPU_CHECK_OK)
1172 dump_check_warn(t->dev, ret);
1178 static int prepare_task(struct ipu_task_entry *t)
1182 ret = check_task(t);
1183 if (ret > IPU_CHECK_ERR_MIN)
1186 if (t->set.mode & VDI_MODE) {
1187 t->task_id = IPU_TASK_ID_VF;
1188 t->set.task = VDI_VF;
1189 if (t->set.mode & ROT_MODE)
1190 t->set.task |= ROT_VF;
1193 if (VDOA_MODE == t->set.mode) {
1194 if (t->set.task != 0) {
1195 dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
1199 t->set.task |= VDOA_ONLY;
1202 if (VDOA_BAND_MODE & t->set.mode) {
1203 /* to save band size: 1<<3 = 8 lines */
1204 t->set.band_lines = 3;
1212 static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
1216 uint32_t status_rot;
1219 status = ipu_channel_status(ipu, MEM_VDI_PRP_VF_MEM);
1220 status_vf = ipu_channel_status(ipu, MEM_PRP_VF_MEM);
1221 status_rot = ipu_channel_status(ipu, MEM_ROT_VF_MEM);
1222 return status || status_vf || status_rot;
1224 status = ipu_channel_status(ipu, MEM_PP_MEM);
1225 status_rot = ipu_channel_status(ipu, MEM_ROT_PP_MEM);
1226 return status || status_rot;
1230 static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
1233 struct ipu_soc *ipu;
1235 uint32_t found_ipu = 0;
1236 uint32_t found_vdoa = 0;
1237 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1239 mutex_lock(&tbl->lock);
1240 if (t->set.mode & VDOA_MODE) {
1241 if (NULL != t->vdoa_handle)
1244 found_vdoa = tbl->vdoa_used ? 0 : 1;
1247 vdoa_get_handle(&t->vdoa_handle);
1249 /* first get vdoa->ipu resource sequence */
1251 if (t->set.task & VDOA_ONLY)
1256 for (i = 0; i < max_ipu_no; i++) {
1257 ipu = ipu_get_soc(i);
1259 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1260 t->task_no, found_vdoa, i);
1262 used = &tbl->used[i][IPU_PP_CH_VF];
1263 if (t->set.mode & VDI_MODE) {
1269 } else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1271 t->task_id = IPU_TASK_ID_VF;
1272 if (t->set.mode & IC_MODE)
1273 t->set.task |= IC_VF;
1274 if (t->set.mode & ROT_MODE)
1275 t->set.task |= ROT_VF;
1281 dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n",
1282 t->task_no, found_vdoa, t->set.mode);
1287 for (i = 0; i < max_ipu_no; i++) {
1288 ipu = ipu_get_soc(i);
1290 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1291 t->task_no, found_vdoa, i);
1293 if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1294 used = &tbl->used[i][IPU_PP_CH_PP];
1296 t->task_id = IPU_TASK_ID_PP;
1297 if (t->set.mode & IC_MODE)
1298 t->set.task |= IC_PP;
1299 if (t->set.mode & ROT_MODE)
1300 t->set.task |= ROT_PP;
1313 if (atomic_inc_return(&t->res_get) == 2)
1315 "ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
1316 t->task_no, found_vdoa);
1320 "%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
1321 __func__, t->task_no, found_vdoa, found_ipu);
1322 mutex_unlock(&tbl->lock);
1323 if (t->set.task & VDOA_ONLY)
1325 else if (t->set.mode & VDOA_MODE)
1326 return found_vdoa && found_ipu;
1331 static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
1334 int rel_vdoa = 0, rel_ipu = 0;
1335 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1337 mutex_lock(&tbl->lock);
1338 if (tsk->set.mode & VDOA_MODE) {
1339 if (!tbl->vdoa_used && tsk->vdoa_handle)
1341 "ERR no:0x%x,vdoa not used,mode:0x%x\n",
1342 tsk->task_no, tsk->set.mode);
1343 if (tbl->vdoa_used && tsk->vdoa_handle) {
1345 vdoa_put_handle(&tsk->vdoa_handle);
1347 tsk->ipu->vdoa_en = 0;
1349 if (vdoa_only || (tsk->set.task & VDOA_ONLY))
1354 tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
1356 ret = atomic_inc_return(&tsk->res_free);
1359 "ERR no:0x%x,rel_vdoa:%d,put ipu twice\n",
1360 tsk->task_no, rel_vdoa);
1363 "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
1364 __func__, tsk->task_no, rel_vdoa, rel_ipu);
1365 mutex_unlock(&tbl->lock);
1368 static int get_vdoa_ipu_res(struct ipu_task_entry *t)
1373 found = _get_vdoa_ipu_res(t);
1377 /* blocking to get resource */
1378 ret = atomic_inc_return(&req_cnt);
1380 "wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
1381 ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
1382 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
1384 dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
1385 t, t->task_no, t->timeout - DEF_DELAY_MS);
1387 t->state = STATE_RES_TIMEOUT;
1390 if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
1392 "ERR[no-0x%x] can not get ipu!\n",
1394 ret = atomic_read(&req_cnt);
1396 ret = atomic_dec_return(&req_cnt);
1399 "ERR[no-0x%x] req_cnt:%d mismatch!\n",
1401 dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n",
1402 t->task_no, t, ret);
1411 static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
1413 struct ipu_task_entry *tsk;
1415 tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
1417 return ERR_PTR(-ENOMEM);
1418 kref_init(&tsk->refcount);
1419 tsk->state = -EINVAL;
1422 tsk->input = task->input;
1423 tsk->output = task->output;
1424 tsk->overlay_en = task->overlay_en;
1425 if (tsk->overlay_en)
1426 tsk->overlay = task->overlay;
1427 if (task->timeout > DEF_TIMEOUT_MS)
1428 tsk->timeout = task->timeout;
1430 tsk->timeout = DEF_TIMEOUT_MS;
1435 static void task_mem_free(struct kref *ref)
1437 struct ipu_task_entry *tsk =
1438 container_of(ref, struct ipu_task_entry, refcount);
1442 int create_split_child_task(struct ipu_split_task *sp_task)
1445 struct ipu_task_entry *tsk;
1447 tsk = create_task_entry(&sp_task->task);
1449 return PTR_ERR(tsk);
1451 sp_task->child_task = tsk;
1452 tsk->task_no = sp_task->task_no;
1454 ret = prepare_task(tsk);
1458 tsk->parent = sp_task->parent_task;
1459 tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
1461 list_add(&tsk->node, &tsk->parent->split_list);
1462 dev_dbg(tsk->dev, "[0x%p] sp_tsk Q list,no-0x%x\n", tsk, tsk->task_no);
1463 tsk->state = STATE_QUEUE;
1464 CHECK_PERF(&tsk->ts_queue);
1469 static inline int sp_task_check_done(struct ipu_split_task *sp_task,
1470 struct ipu_task_entry *parent, int num, int *idx)
1474 struct ipu_task_entry *tsk;
1475 struct mutex *lock = &parent->split_lock;
1479 for (i = 0; i < num; i++) {
1480 tsk = sp_task[i].child_task;
1481 if (tsk && tsk->split_done) {
1493 static int create_split_task(
1495 struct ipu_split_task *sp_task)
1497 struct ipu_task *task = &(sp_task->task);
1498 struct ipu_task_entry *t = sp_task->parent_task;
1501 sp_task->task_no |= stripe;
1503 task->input = t->input;
1504 task->output = t->output;
1505 task->overlay_en = t->overlay_en;
1506 if (task->overlay_en)
1507 task->overlay = t->overlay;
1508 task->task_id = t->task_id;
1509 if ((t->set.split_mode == RL_SPLIT) ||
1510 (t->set.split_mode == UD_SPLIT))
1511 task->timeout = t->timeout / 2;
1513 task->timeout = t->timeout / 4;
1515 task->input.crop.w = t->set.sp_setting.iw;
1516 task->input.crop.h = t->set.sp_setting.ih;
1517 if (task->overlay_en) {
1518 task->overlay.crop.w = t->set.sp_setting.ow;
1519 task->overlay.crop.h = t->set.sp_setting.oh;
1521 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1522 task->output.crop.w = t->set.sp_setting.oh;
1523 task->output.crop.h = t->set.sp_setting.ow;
1524 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos;
1525 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos;
1528 task->output.crop.w = t->set.sp_setting.ow;
1529 task->output.crop.h = t->set.sp_setting.oh;
1530 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos;
1531 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos;
1534 if (stripe & LEFT_STRIPE)
1535 task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
1536 else if (stripe & RIGHT_STRIPE)
1537 task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
1538 if (stripe & UP_STRIPE)
1539 task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
1540 else if (stripe & DOWN_STRIPE)
1541 task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
1543 if (task->overlay_en) {
1544 if (stripe & LEFT_STRIPE)
1545 task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
1546 else if (stripe & RIGHT_STRIPE)
1547 task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
1548 if (stripe & UP_STRIPE)
1549 task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
1550 else if (stripe & DOWN_STRIPE)
1551 task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1554 switch (t->output.rotate) {
1555 case IPU_ROTATE_NONE:
1556 if (stripe & LEFT_STRIPE)
1557 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1558 else if (stripe & RIGHT_STRIPE)
1559 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1560 if (stripe & UP_STRIPE)
1561 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1562 else if (stripe & DOWN_STRIPE)
1563 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1565 case IPU_ROTATE_VERT_FLIP:
1566 if (stripe & LEFT_STRIPE)
1567 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1568 else if (stripe & RIGHT_STRIPE)
1569 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1570 if (stripe & UP_STRIPE)
1571 task->output.crop.pos.y =
1572 t->output.crop.pos.y + t->output.crop.h
1573 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1574 else if (stripe & DOWN_STRIPE)
1575 task->output.crop.pos.y =
1576 t->output.crop.pos.y + t->output.crop.h
1577 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1579 case IPU_ROTATE_HORIZ_FLIP:
1580 if (stripe & LEFT_STRIPE)
1581 task->output.crop.pos.x =
1582 t->output.crop.pos.x + t->output.crop.w
1583 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1584 else if (stripe & RIGHT_STRIPE)
1585 task->output.crop.pos.x =
1586 t->output.crop.pos.x + t->output.crop.w
1587 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1588 if (stripe & UP_STRIPE)
1589 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1590 else if (stripe & DOWN_STRIPE)
1591 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1593 case IPU_ROTATE_180:
1594 if (stripe & LEFT_STRIPE)
1595 task->output.crop.pos.x =
1596 t->output.crop.pos.x + t->output.crop.w
1597 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1598 else if (stripe & RIGHT_STRIPE)
1599 task->output.crop.pos.x =
1600 t->output.crop.pos.x + t->output.crop.w
1601 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1602 if (stripe & UP_STRIPE)
1603 task->output.crop.pos.y =
1604 t->output.crop.pos.y + t->output.crop.h
1605 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1606 else if (stripe & DOWN_STRIPE)
1607 task->output.crop.pos.y =
1608 t->output.crop.pos.y + t->output.crop.h
1609 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1611 case IPU_ROTATE_90_RIGHT:
1612 if (stripe & UP_STRIPE)
1613 task->output.crop.pos.x =
1614 t->output.crop.pos.x + t->output.crop.w
1615 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1616 else if (stripe & DOWN_STRIPE)
1617 task->output.crop.pos.x =
1618 t->output.crop.pos.x + t->output.crop.w
1619 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1620 if (stripe & LEFT_STRIPE)
1621 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1622 else if (stripe & RIGHT_STRIPE)
1623 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1625 case IPU_ROTATE_90_RIGHT_HFLIP:
1626 if (stripe & UP_STRIPE)
1627 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1628 else if (stripe & DOWN_STRIPE)
1629 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1630 if (stripe & LEFT_STRIPE)
1631 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1632 else if (stripe & RIGHT_STRIPE)
1633 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1635 case IPU_ROTATE_90_RIGHT_VFLIP:
1636 if (stripe & UP_STRIPE)
1637 task->output.crop.pos.x =
1638 t->output.crop.pos.x + t->output.crop.w
1639 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1640 else if (stripe & DOWN_STRIPE)
1641 task->output.crop.pos.x =
1642 t->output.crop.pos.x + t->output.crop.w
1643 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1644 if (stripe & LEFT_STRIPE)
1645 task->output.crop.pos.y =
1646 t->output.crop.pos.y + t->output.crop.h
1647 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1648 else if (stripe & RIGHT_STRIPE)
1649 task->output.crop.pos.y =
1650 t->output.crop.pos.y + t->output.crop.h
1651 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1653 case IPU_ROTATE_90_LEFT:
1654 if (stripe & UP_STRIPE)
1655 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1656 else if (stripe & DOWN_STRIPE)
1657 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1658 if (stripe & LEFT_STRIPE)
1659 task->output.crop.pos.y =
1660 t->output.crop.pos.y + t->output.crop.h
1661 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1662 else if (stripe & RIGHT_STRIPE)
1663 task->output.crop.pos.y =
1664 t->output.crop.pos.y + t->output.crop.h
1665 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1668 dev_err(t->dev, "ERR:should not be here\n");
1672 ret = create_split_child_task(sp_task);
1674 dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
1678 static int queue_split_task(struct ipu_task_entry *t,
1679 struct ipu_split_task *sp_task, uint32_t size)
1684 struct ipu_task_entry *tsk = NULL;
1685 struct mutex *lock = &t->split_lock;
1687 dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
1688 t, t->task_no, size);
1690 init_waitqueue_head(&t->split_waitq);
1691 INIT_LIST_HEAD(&t->split_list);
1692 for (j = 0; j < size; j++) {
1693 memset(&sp_task[j], 0, sizeof(*sp_task));
1694 sp_task[j].parent_task = t;
1695 sp_task[j].task_no = t->task_no;
1698 if (t->set.split_mode == RL_SPLIT) {
1700 err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
1704 err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
1705 } else if (t->set.split_mode == UD_SPLIT) {
1707 err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
1711 err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
1714 err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1718 err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1722 err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
1726 err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
1730 for (j = 0; j < (i + 1); j++) {
1732 if (sp_task[j].child_task)
1734 "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
1735 j, sp_task[j].child_task->task_no,
1736 sp_task[j].child_task->state, err[j]);
1739 dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
1740 sp_task[j].child_task, j, sp_task[j].child_task->task_no,
1741 state_msg[sp_task[j].child_task->state].msg, err[j]);
1747 for (j = 0; j < (i + 1); j++) {
1748 if (err[j] < 0 && !ret)
1750 tsk = sp_task[j].child_task;
1755 t->state = STATE_ERR;
1760 static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
1761 ipu_channel_t channel, uint32_t ch_type)
1766 dma_addr_t inbuf_base = 0;
1768 struct vdoa_params param;
1769 struct vdoa_ipu_buf buf;
1770 struct ipu_soc *ipu_idx;
1771 u32 ipu_stride, obuf_size;
1775 if ((IPU_PIX_FMT_YUYV != t->output.format) &&
1776 (IPU_PIX_FMT_NV12 != t->output.format)) {
1777 dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
1781 memset(¶m, 0, sizeof(param));
1782 /* init channel tiled bufs */
1783 if (deinterlace_3_field(t) &&
1784 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1785 field_size = tiled_filed_size(t);
1786 if (INPUT_CHAN_VDI_P == ch_type) {
1787 inbuf_base = t->input.paddr + field_size;
1788 param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
1789 } else if (INPUT_CHAN == ch_type) {
1790 inbuf_base = t->input.paddr_n;
1791 param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
1792 } else if (INPUT_CHAN_VDI_N == ch_type) {
1793 inbuf_base = t->input.paddr_n + field_size;
1794 param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
1797 height = t->input.crop.h >> 1; /* field format for vdoa */
1798 width = t->input.crop.w;
1799 param.vfield_buf.vubo = t->set.i_uoff;
1800 param.interlaced = 1;
1801 param.scan_order = 1;
1802 type = IPU_INPUT_BUFFER;
1803 } else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
1804 (INPUT_CHAN == ch_type)) {
1805 height = t->input.crop.h;
1806 width = t->input.crop.w;
1807 param.vframe_buf.veba = t->input.paddr + t->set.i_off;
1808 param.vframe_buf.vubo = t->set.i_uoff;
1809 type = IPU_INPUT_BUFFER;
1813 param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
1814 if (param.band_mode && (t->set.band_lines != 3) &&
1815 (t->set.band_lines != 4) && (t->set.band_lines != 5))
1817 else if (param.band_mode)
1818 param.band_lines = (1 << t->set.band_lines);
1819 for (i = 0; i < max_ipu_no; i++) {
1820 ipu_idx = ipu_get_soc(i);
1821 if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
1824 if (t->set.task & VDOA_ONLY)
1825 /* dummy, didn't need ipu res */
1827 if (max_ipu_no == i) {
1828 dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
1833 param.vpu_stride = t->input.width;
1834 param.height = height;
1835 param.width = width;
1836 if (IPU_PIX_FMT_NV12 == t->output.format)
1837 param.pfs = VDOA_PFS_NV12;
1839 param.pfs = VDOA_PFS_YUYV;
1840 ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
1842 ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
1843 obuf_size = PAGE_ALIGN(param.width * param.height *
1844 fmt_to_bpp(ipu_fmt)/8);
1845 dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
1846 param.band_mode, param.band_lines);
1847 if (!param.band_mode) {
1848 /* note: if only for tiled -> raster convert and
1849 no other post-processing, we don't need alloc buf
1850 and use output buffer directly.
1852 if (t->set.task & VDOA_ONLY)
1853 param.ieba0 = t->output.paddr;
1855 dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
1859 if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
1860 dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
1864 ret = vdoa_setup(t->vdoa_handle, ¶m);
1867 vdoa_get_output_buf(t->vdoa_handle, &buf);
1868 if (t->set.task & VDOA_ONLY)
1871 ret = ipu_init_channel_buffer(ipu,
1885 t->state = STATE_INIT_CHAN_BUF_FAIL;
1889 if (param.band_mode) {
1890 ret = ipu_set_channel_bandmode(ipu, channel,
1891 type, t->set.band_lines);
1893 t->state = STATE_INIT_CHAN_BAND_FAIL;
1901 static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
1905 if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
1906 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1907 CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
1908 } else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
1909 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1910 CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
1911 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
1913 CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
1914 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
1916 CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
1919 dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n",
1920 t->task_no, t->input.format);
1927 static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
1930 ipu_channel_params_t params;
1931 dma_addr_t inbuf = 0, ovbuf = 0, ov_alp_buf = 0;
1932 dma_addr_t inbuf_p = 0, inbuf_n = 0;
1933 dma_addr_t outbuf = 0;
1934 int out_uoff = 0, out_voff = 0, out_rot;
1935 int out_w = 0, out_h = 0, out_stride;
1937 u32 vdi_frame_idx = 0;
1939 memset(¶ms, 0, sizeof(params));
1941 /* is it need link a rot channel */
1942 if (ic_and_rot(t->set.mode)) {
1943 outbuf = t->set.r_paddr;
1944 out_w = t->set.r_width;
1945 out_h = t->set.r_height;
1946 out_stride = t->set.r_stride;
1947 out_fmt = t->set.r_fmt;
1950 out_rot = IPU_ROTATE_NONE;
1952 outbuf = t->output.paddr + t->set.o_off;
1953 out_w = t->output.crop.w;
1954 out_h = t->output.crop.h;
1955 out_stride = t->set.ostride;
1956 out_fmt = t->output.format;
1957 out_uoff = t->set.o_uoff;
1958 out_voff = t->set.o_voff;
1959 out_rot = t->output.rotate;
1963 params.mem_prp_vf_mem.in_width = t->input.crop.w;
1964 params.mem_prp_vf_mem.out_width = out_w;
1965 params.mem_prp_vf_mem.in_height = t->input.crop.h;
1966 params.mem_prp_vf_mem.out_height = out_h;
1967 params.mem_prp_vf_mem.in_pixel_fmt = t->input.format;
1968 params.mem_prp_vf_mem.out_pixel_fmt = out_fmt;
1969 params.mem_prp_vf_mem.motion_sel = t->input.deinterlace.motion;
1971 params.mem_prp_vf_mem.outh_resize_ratio =
1972 t->set.sp_setting.outh_resize_ratio;
1973 params.mem_prp_vf_mem.outv_resize_ratio =
1974 t->set.sp_setting.outv_resize_ratio;
1976 if (t->overlay_en) {
1977 params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
1978 params.mem_prp_vf_mem.graphics_combine_en = 1;
1979 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
1980 params.mem_prp_vf_mem.global_alpha_en = 1;
1981 else if (t->overlay.alpha.loc_alp_paddr)
1982 params.mem_prp_vf_mem.alpha_chan_en = 1;
1983 /* otherwise, alpha bending per pixel is used. */
1984 params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
1985 if (t->overlay.colorkey.enable) {
1986 params.mem_prp_vf_mem.key_color_en = 1;
1987 params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
1991 if (t->input.deinterlace.enable) {
1992 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_FIELD_MASK)
1993 params.mem_prp_vf_mem.field_fmt =
1994 IPU_DEINTERLACE_FIELD_BOTTOM;
1996 params.mem_prp_vf_mem.field_fmt =
1997 IPU_DEINTERLACE_FIELD_TOP;
1999 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
2000 vdi_frame_idx = t->input.deinterlace.field_fmt &
2001 IPU_DEINTERLACE_RATE_FRAME1;
2004 if (t->set.mode & VDOA_MODE)
2008 if (!(t->set.task & VDOA_ONLY)) {
2009 ret = ipu_init_channel(ipu, t->set.ic_chan, ¶ms);
2011 t->state = STATE_INIT_CHAN_FAIL;
2016 if (deinterlace_3_field(t)) {
2017 ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, ¶ms);
2019 t->state = STATE_INIT_CHAN_FAIL;
2022 ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, ¶ms);
2024 t->state = STATE_INIT_CHAN_FAIL;
2029 /* init channel bufs */
2030 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
2031 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
2032 ret = init_tiled_ch_bufs(ipu, t);
2036 if ((deinterlace_3_field(t)) &&
2037 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2038 if (params.mem_prp_vf_mem.field_fmt ==
2039 IPU_DEINTERLACE_FIELD_TOP) {
2040 if (vdi_frame_idx) {
2041 inbuf_p = t->input.paddr + t->set.istride +
2043 inbuf = t->input.paddr_n + t->set.i_off;
2044 inbuf_n = t->input.paddr_n + t->set.istride +
2046 params.mem_prp_vf_mem.field_fmt =
2047 IPU_DEINTERLACE_FIELD_BOTTOM;
2049 inbuf_p = t->input.paddr + t->set.i_off;
2050 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2051 inbuf_n = t->input.paddr_n + t->set.i_off;
2054 if (vdi_frame_idx) {
2055 inbuf_p = t->input.paddr + t->set.i_off;
2056 inbuf = t->input.paddr_n + t->set.istride + t->set.i_off;
2057 inbuf_n = t->input.paddr_n + t->set.i_off;
2058 params.mem_prp_vf_mem.field_fmt =
2059 IPU_DEINTERLACE_FIELD_TOP;
2061 inbuf_p = t->input.paddr + t->set.istride +
2063 inbuf = t->input.paddr + t->set.i_off;
2064 inbuf_n = t->input.paddr_n + t->set.istride +
2069 if (t->input.deinterlace.enable) {
2070 if (params.mem_prp_vf_mem.field_fmt ==
2071 IPU_DEINTERLACE_FIELD_TOP) {
2072 if (vdi_frame_idx) {
2073 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2074 params.mem_prp_vf_mem.field_fmt =
2075 IPU_DEINTERLACE_FIELD_BOTTOM;
2077 inbuf = t->input.paddr + t->set.i_off;
2079 if (vdi_frame_idx) {
2080 inbuf = t->input.paddr + t->set.i_off;
2081 params.mem_prp_vf_mem.field_fmt =
2082 IPU_DEINTERLACE_FIELD_TOP;
2084 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2087 inbuf = t->input.paddr + t->set.i_off;
2091 ovbuf = t->overlay.paddr + t->set.ov_off;
2093 if (t->overlay_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
2094 ov_alp_buf = t->overlay.alpha.loc_alp_paddr
2095 + t->set.ov_alpha_off;
2097 if ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
2098 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2099 ret = ipu_init_channel_buffer(ipu,
2113 t->state = STATE_INIT_CHAN_BUF_FAIL;
2117 if (deinterlace_3_field(t) &&
2118 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2119 ret = ipu_init_channel_buffer(ipu,
2120 t->set.vdi_ic_p_chan,
2133 t->state = STATE_INIT_CHAN_BUF_FAIL;
2137 ret = ipu_init_channel_buffer(ipu,
2138 t->set.vdi_ic_n_chan,
2151 t->state = STATE_INIT_CHAN_BUF_FAIL;
2156 if (t->overlay_en) {
2157 ret = ipu_init_channel_buffer(ipu,
2159 IPU_GRAPH_IN_BUFFER,
2171 t->state = STATE_INIT_CHAN_BUF_FAIL;
2176 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2177 ret = ipu_init_channel_buffer(ipu,
2179 IPU_ALPHA_IN_BUFFER,
2180 IPU_PIX_FMT_GENERIC,
2183 t->set.ov_alpha_stride,
2190 t->state = STATE_INIT_CHAN_BUF_FAIL;
2195 if (!(t->set.task & VDOA_ONLY)) {
2196 ret = ipu_init_channel_buffer(ipu,
2210 t->state = STATE_INIT_CHAN_BUF_FAIL;
2215 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2216 ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2217 CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
2218 STATE_LINK_CHAN_FAIL, done, ret);
2225 static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
2229 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2230 ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2231 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
2232 STATE_UNLINK_CHAN_FAIL, ret);
2234 ipu_uninit_channel(ipu, t->set.ic_chan);
2235 if (deinterlace_3_field(t)) {
2236 ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
2237 ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
2241 static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2244 dma_addr_t inbuf = 0, outbuf = 0;
2245 int in_uoff = 0, in_voff = 0;
2246 int in_fmt, in_width, in_height, in_stride;
2249 ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
2251 t->state = STATE_INIT_CHAN_FAIL;
2255 /* init channel buf */
2256 /* is it need link to a ic channel */
2257 if (ic_and_rot(t->set.mode)) {
2258 in_fmt = t->set.r_fmt;
2259 in_width = t->set.r_width;
2260 in_height = t->set.r_height;
2261 in_stride = t->set.r_stride;
2262 inbuf = t->set.r_paddr;
2266 in_fmt = t->input.format;
2267 in_width = t->input.crop.w;
2268 in_height = t->input.crop.h;
2269 in_stride = t->set.istride;
2270 inbuf = t->input.paddr + t->set.i_off;
2271 in_uoff = t->set.i_uoff;
2272 in_voff = t->set.i_voff;
2274 outbuf = t->output.paddr + t->set.o_off;
2276 ret = ipu_init_channel_buffer(ipu,
2290 t->state = STATE_INIT_CHAN_BUF_FAIL;
2294 ret = ipu_init_channel_buffer(ipu,
2308 t->state = STATE_INIT_CHAN_BUF_FAIL;
2316 static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2318 ipu_uninit_channel(ipu, t->set.rot_chan);
2321 static int get_irq(struct ipu_task_entry *t)
2326 if (only_ic(t->set.mode))
2327 chan = t->set.ic_chan;
2329 chan = t->set.rot_chan;
2332 case MEM_ROT_VF_MEM:
2333 irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
2335 case MEM_ROT_PP_MEM:
2336 irq = IPU_IRQ_PP_ROT_OUT_EOF;
2338 case MEM_VDI_PRP_VF_MEM:
2339 case MEM_PRP_VF_MEM:
2340 irq = IPU_IRQ_PRP_VF_OUT_EOF;
2343 irq = IPU_IRQ_PP_OUT_EOF;
2346 irq = IPU_IRQ_VDIC_OUT_EOF;
2355 static irqreturn_t task_irq_handler(int irq, void *dev_id)
2357 struct ipu_task_entry *prev_tsk = dev_id;
2359 CHECK_PERF(&prev_tsk->ts_inirq);
2360 complete(&prev_tsk->irq_comp);
2361 dev_dbg(prev_tsk->dev, "[0x%p] no-0x%x in-irq!",
2362 prev_tsk, prev_tsk->task_no);
2367 /* Fix deinterlace up&down split mode medium line */
2368 static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
2375 unsigned char *base_off;
2376 struct ipu_task_entry *parent = t->parent;
2379 dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
2382 stripe_mode = t->task_no & 0xf;
2383 task_no = t->task_no >> 4;
2385 base_off = (char *) __va(t->output.paddr);
2386 if (base_off == NULL) {
2387 dev_err(t->dev, "ERR[0x%p]Falied get vitual address\n", t);
2391 vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
2392 vdi_size = vdi_save_lines * t->output.crop.w * 2;
2394 if (vdi_save_lines <= 0) {
2395 dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
2399 /*check vditmpbuf buffer have alloced or buffer size is changed */
2400 if ((vdi_save_lines != parent->old_save_lines) ||
2401 (vdi_size != parent->old_size)) {
2402 if (parent->vditmpbuf[0] != NULL)
2403 kfree(parent->vditmpbuf[0]);
2404 if (parent->vditmpbuf[1] != NULL)
2405 kfree(parent->vditmpbuf[1]);
2407 parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
2408 if (parent->vditmpbuf[0] == NULL) {
2410 "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
2413 memset(parent->vditmpbuf[0], 0, vdi_size);
2415 parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
2416 if (parent->vditmpbuf[1] == NULL) {
2418 "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
2421 memset(parent->vditmpbuf[1], 0, vdi_size);
2423 parent->old_save_lines = vdi_save_lines;
2424 parent->old_size = vdi_size;
2427 /* UP stripe or UP&LEFT stripe */
2428 if ((stripe_mode == UP_STRIPE) ||
2429 (stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
2430 if (!parent->buf0filled) {
2431 offset_addr = t->set.o_off +
2432 t->set.sp_setting.ud_split_line*t->set.ostride;
2433 dmac_flush_range(base_off + offset_addr,
2434 base_off + offset_addr + vdi_size);
2435 outer_flush_range(t->output.paddr + offset_addr,
2436 t->output.paddr + offset_addr + vdi_size);
2438 for (i = 0; i < vdi_save_lines; i++)
2439 memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
2440 base_off + offset_addr +
2441 i*t->set.ostride, t->output.crop.w*2);
2442 parent->buf0filled = true;
2444 offset_addr = t->set.o_off + (t->output.crop.h -
2445 vdi_save_lines) * t->set.ostride;
2446 for (i = 0; i < vdi_save_lines; i++)
2447 memcpy(base_off + offset_addr + i*t->set.ostride,
2448 parent->vditmpbuf[0] + i*t->output.crop.w*2,
2449 t->output.crop.w*2);
2451 dmac_flush_range(base_off + offset_addr,
2452 base_off + offset_addr + i*t->set.ostride);
2453 outer_flush_range(t->output.paddr + offset_addr,
2454 t->output.paddr + offset_addr + i*t->set.ostride);
2455 parent->buf0filled = false;
2458 /*Down stripe or Down&Left stripe*/
2459 else if ((stripe_mode == DOWN_STRIPE) ||
2460 (stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
2461 if (!parent->buf0filled) {
2462 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2463 dmac_flush_range(base_off + offset_addr,
2464 base_off + offset_addr + vdi_size);
2465 outer_flush_range(t->output.paddr + offset_addr,
2466 t->output.paddr + offset_addr + vdi_size);
2468 for (i = 0; i < vdi_save_lines; i++)
2469 memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
2470 base_off + offset_addr + i*t->set.ostride,
2471 t->output.crop.w*2);
2472 parent->buf0filled = true;
2474 offset_addr = t->set.o_off;
2475 for (i = 0; i < vdi_save_lines; i++)
2476 memcpy(base_off + offset_addr + i*t->set.ostride,
2477 parent->vditmpbuf[0] + i*t->output.crop.w*2,
2478 t->output.crop.w*2);
2480 dmac_flush_range(base_off + offset_addr,
2481 base_off + offset_addr + i*t->set.ostride);
2482 outer_flush_range(t->output.paddr + offset_addr,
2483 t->output.paddr + offset_addr + i*t->set.ostride);
2484 parent->buf0filled = false;
2488 else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
2489 if (!parent->buf1filled) {
2490 offset_addr = t->set.o_off +
2491 t->set.sp_setting.ud_split_line*t->set.ostride;
2492 dmac_flush_range(base_off + offset_addr,
2493 base_off + offset_addr + vdi_size);
2494 outer_flush_range(t->output.paddr + offset_addr,
2495 t->output.paddr + offset_addr + vdi_size);
2497 for (i = 0; i < vdi_save_lines; i++)
2498 memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
2499 base_off + offset_addr + i*t->set.ostride,
2500 t->output.crop.w*2);
2501 parent->buf1filled = true;
2503 offset_addr = t->set.o_off +
2504 (t->output.crop.h - vdi_save_lines)*t->set.ostride;
2505 for (i = 0; i < vdi_save_lines; i++)
2506 memcpy(base_off + offset_addr + i*t->set.ostride,
2507 parent->vditmpbuf[1] + i*t->output.crop.w*2,
2508 t->output.crop.w*2);
2510 dmac_flush_range(base_off + offset_addr,
2511 base_off + offset_addr + i*t->set.ostride);
2512 outer_flush_range(t->output.paddr + offset_addr,
2513 t->output.paddr + offset_addr + i*t->set.ostride);
2514 parent->buf1filled = false;
2517 /*Down stripe or Down&Right stript*/
2518 else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
2519 if (!parent->buf1filled) {
2520 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2521 dmac_flush_range(base_off + offset_addr,
2522 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2523 outer_flush_range(t->output.paddr + offset_addr,
2524 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2526 for (i = 0; i < vdi_save_lines; i++)
2527 memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
2528 base_off + offset_addr + i*t->set.ostride,
2529 t->output.crop.w*2);
2530 parent->buf1filled = true;
2532 offset_addr = t->set.o_off;
2533 for (i = 0; i < vdi_save_lines; i++)
2534 memcpy(base_off + offset_addr + i*t->set.ostride,
2535 parent->vditmpbuf[1] + i*t->output.crop.w*2,
2536 t->output.crop.w*2);
2538 dmac_flush_range(base_off + offset_addr,
2539 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2540 outer_flush_range(t->output.paddr + offset_addr,
2541 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2542 parent->buf1filled = false;
2547 static void do_task_release(struct ipu_task_entry *t, int fail)
2550 struct ipu_soc *ipu = t->ipu;
2552 if (t->input.deinterlace.enable && !fail &&
2553 (t->task_no & (UP_STRIPE | DOWN_STRIPE)))
2554 vdi_split_process(ipu, t);
2556 ipu_free_irq(ipu, t->irq, t);
2558 if (t->vdoa_dma.vaddr)
2559 dma_free_coherent(t->dev,
2564 if (only_ic(t->set.mode)) {
2565 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2566 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
2567 STATE_DISABLE_CHAN_FAIL, ret);
2568 if (deinterlace_3_field(t)) {
2569 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2571 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_p",
2572 STATE_DISABLE_CHAN_FAIL, ret);
2573 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2575 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_n",
2576 STATE_DISABLE_CHAN_FAIL, ret);
2578 } else if (only_rot(t->set.mode)) {
2579 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2580 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_rot",
2581 STATE_DISABLE_CHAN_FAIL, ret);
2582 } else if (ic_and_rot(t->set.mode)) {
2583 ret = ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan);
2584 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch",
2585 STATE_UNLINK_CHAN_FAIL, ret);
2586 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2587 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-rot",
2588 STATE_DISABLE_CHAN_FAIL, ret);
2589 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2590 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-ic",
2591 STATE_DISABLE_CHAN_FAIL, ret);
2592 if (deinterlace_3_field(t)) {
2593 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2595 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-p",
2596 STATE_DISABLE_CHAN_FAIL, ret);
2597 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2599 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-n",
2600 STATE_DISABLE_CHAN_FAIL, ret);
2604 if (only_ic(t->set.mode))
2606 else if (only_rot(t->set.mode))
2608 else if (ic_and_rot(t->set.mode)) {
2613 t->state = STATE_OK;
2614 CHECK_PERF(&t->ts_rel);
2618 static void do_task_vdoa_only(struct ipu_task_entry *t)
2622 ret = init_tiled_ch_bufs(NULL, t);
2623 CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
2624 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2625 vdoa_stop(t->vdoa_handle);
2626 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
2627 STATE_VDOA_IRQ_TIMEOUT, out, ret);
2629 t->state = STATE_OK;
2634 static void do_task(struct ipu_task_entry *t)
2640 struct ipu_soc *ipu = t->ipu;
2642 CHECK_PERF(&t->ts_dotask);
2645 t->state = STATE_NO_IPU;
2649 init_completion(&t->irq_comp);
2650 dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
2651 t->task_no, t->task_id);
2654 if (t->set.task & IC_PP) {
2655 t->set.ic_chan = MEM_PP_MEM;
2656 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
2657 } else if (t->set.task & IC_VF) {
2658 t->set.ic_chan = MEM_PRP_VF_MEM;
2659 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
2660 } else if (t->set.task & VDI_VF) {
2661 if (t->set.mode & VDOA_BAND_MODE) {
2662 t->set.ic_chan = MEM_VDI_MEM;
2663 if (deinterlace_3_field(t)) {
2664 t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
2665 t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
2667 dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
2670 t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
2671 if (deinterlace_3_field(t)) {
2672 t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
2673 t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
2676 "[0x%p]ic ch MEM_VDI_PRP_VF_MEM\n", t);
2680 if (t->set.task & ROT_PP) {
2681 t->set.rot_chan = MEM_ROT_PP_MEM;
2682 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
2683 } else if (t->set.task & ROT_VF) {
2684 t->set.rot_chan = MEM_ROT_VF_MEM;
2685 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
2688 if (t->task_id == IPU_TASK_ID_VF)
2689 busy = ic_vf_pp_is_busy(ipu, true);
2690 else if (t->task_id == IPU_TASK_ID_PP)
2691 busy = ic_vf_pp_is_busy(ipu, false);
2693 dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n",
2694 t->task_no, t->task_id);
2698 dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n",
2699 (void *)t, t->task_no, t->task_id);
2700 t->state = STATE_IPU_BUSY;
2706 t->state = STATE_NO_IRQ;
2712 if (only_ic(t->set.mode)) {
2713 dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
2714 ret = init_ic(ipu, t);
2715 CHECK_RETCODE(ret < 0, "init_ic only_ic",
2716 t->state, chan_setup, ret);
2717 } else if (only_rot(t->set.mode)) {
2718 dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
2719 ret = init_rot(ipu, t);
2720 CHECK_RETCODE(ret < 0, "init_rot only_rot",
2721 t->state, chan_setup, ret);
2722 } else if (ic_and_rot(t->set.mode)) {
2723 int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1;
2725 dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
2726 t->set.r_fmt = t->output.format;
2727 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
2728 t->set.r_width = t->output.crop.h;
2729 t->set.r_height = t->output.crop.w;
2731 t->set.r_width = t->output.crop.w;
2732 t->set.r_height = t->output.crop.h;
2734 t->set.r_stride = t->set.r_width *
2735 bytes_per_pixel(t->set.r_fmt);
2736 r_size = PAGE_ALIGN(t->set.r_width * t->set.r_height
2737 * fmt_to_bpp(t->set.r_fmt)/8);
2739 if (r_size > ipu->rot_dma[rot_idx].size) {
2740 dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t);
2742 if (ipu->rot_dma[rot_idx].vaddr)
2743 dma_free_coherent(t->dev,
2744 ipu->rot_dma[rot_idx].size,
2745 ipu->rot_dma[rot_idx].vaddr,
2746 ipu->rot_dma[rot_idx].paddr);
2748 ipu->rot_dma[rot_idx].size = r_size;
2749 ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev,
2751 &ipu->rot_dma[rot_idx].paddr,
2752 GFP_DMA | GFP_KERNEL);
2753 CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
2754 "ic_and_rot", STATE_SYS_NO_MEM,
2755 chan_setup, -ENOMEM);
2757 t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
2759 dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
2760 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
2761 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
2762 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
2763 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
2764 dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
2766 ret = init_ic(ipu, t);
2767 CHECK_RETCODE(ret < 0, "init_ic ic_and_rot",
2768 t->state, chan_setup, ret);
2769 ret = init_rot(ipu, t);
2770 CHECK_RETCODE(ret < 0, "init_rot ic_and_rot",
2771 t->state, chan_setup, ret);
2772 ret = ipu_link_channels(ipu, t->set.ic_chan,
2774 CHECK_RETCODE(ret < 0, "ipu_link_ch ic_and_rot",
2775 STATE_LINK_CHAN_FAIL, chan_setup, ret);
2777 dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t);
2778 t->state = STATE_ERR;
2782 ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, t);
2783 CHECK_RETCODE(ret < 0, "ipu_req_irq",
2784 STATE_IRQ_FAIL, chan_setup, ret);
2786 /* enable/start channel */
2787 if (only_ic(t->set.mode)) {
2788 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2789 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic",
2790 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2791 if (deinterlace_3_field(t)) {
2792 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2793 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_p",
2794 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2795 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2796 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_n",
2797 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2800 ret = ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER,
2802 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic",
2803 STATE_SEL_BUF_FAIL, chan_buf, ret);
2804 if (t->overlay_en) {
2805 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2806 IPU_GRAPH_IN_BUFFER, 0);
2807 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_g",
2808 STATE_SEL_BUF_FAIL, chan_buf, ret);
2809 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2810 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2811 IPU_ALPHA_IN_BUFFER, 0);
2812 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_a",
2813 STATE_SEL_BUF_FAIL, chan_buf,
2817 if (!(t->set.mode & VDOA_BAND_MODE)) {
2818 if (deinterlace_3_field(t))
2819 ipu_select_multi_vdi_buffer(ipu, 0);
2821 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2822 IPU_INPUT_BUFFER, 0);
2823 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
2824 STATE_SEL_BUF_FAIL, chan_buf, ret);
2827 } else if (only_rot(t->set.mode)) {
2828 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2829 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_rot",
2830 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2831 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2832 IPU_OUTPUT_BUFFER, 0);
2833 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_o",
2834 STATE_SEL_BUF_FAIL, chan_buf, ret);
2835 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2836 IPU_INPUT_BUFFER, 0);
2837 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_i",
2838 STATE_SEL_BUF_FAIL, chan_buf, ret);
2839 } else if (ic_and_rot(t->set.mode)) {
2840 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2841 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-rot",
2842 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2843 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2844 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-ic",
2845 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2846 if (deinterlace_3_field(t)) {
2847 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2848 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-p",
2849 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2850 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2851 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-n",
2852 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2855 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2856 IPU_OUTPUT_BUFFER, 0);
2857 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-rot-o",
2858 STATE_SEL_BUF_FAIL, chan_buf, ret);
2859 if (t->overlay_en) {
2860 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2861 IPU_GRAPH_IN_BUFFER, 0);
2862 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-g",
2863 STATE_SEL_BUF_FAIL, chan_buf, ret);
2864 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2865 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2866 IPU_ALPHA_IN_BUFFER, 0);
2867 CHECK_RETCODE(ret < 0, "ipu_sel_buf icrot-ic-a",
2872 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2873 IPU_OUTPUT_BUFFER, 0);
2874 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-o",
2875 STATE_SEL_BUF_FAIL, chan_buf, ret);
2876 if (deinterlace_3_field(t))
2877 ipu_select_multi_vdi_buffer(ipu, 0);
2879 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2880 IPU_INPUT_BUFFER, 0);
2881 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-i",
2882 STATE_SEL_BUF_FAIL, chan_buf, ret);
2887 t->state = STATE_IN_PROGRESS;
2889 if (t->set.mode & VDOA_BAND_MODE) {
2890 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2891 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
2892 STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
2895 CHECK_PERF(&t->ts_waitirq);
2896 ret = wait_for_completion_timeout(&t->irq_comp,
2897 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
2898 CHECK_PERF(&t->ts_wakeup);
2899 CHECK_RETCODE(ret == 0, "wait_for_comp_timeout",
2900 STATE_IRQ_TIMEOUT, chan_rel, ret);
2901 dev_dbg(t->dev, "[0x%p] no-0x%x ipu irq done!", t, t->task_no);
2907 if (t->set.mode & VDOA_BAND_MODE)
2908 vdoa_stop(t->vdoa_handle);
2909 do_task_release(t, t->state >= STATE_ERR);
2913 static void do_task_vdoa_vdi(struct ipu_task_entry *t)
2919 /* FIXME: crop mode not support now */
2920 stripe_width = t->input.width >> 1;
2921 t->input.crop.pos.x = 0;
2922 t->input.crop.pos.y = 0;
2923 t->input.crop.w = stripe_width;
2924 t->input.crop.h = t->input.height;
2925 t->output.crop.w = stripe_width;
2926 t->output.crop.h = t->input.height;
2928 for (i = 0; i < 2; i++) {
2929 t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
2930 t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
2932 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
2938 update_offset(t->input.format,
2939 t->input.width, t->input.height,
2940 t->input.crop.pos.x,
2941 t->input.crop.pos.y,
2942 &t->set.i_off, &t->set.i_uoff,
2943 &t->set.i_voff, &t->set.istride);
2944 dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
2945 t->set.i_off, t->set.i_uoff, t->set.istride);
2947 ret = set_crop(&t->output.crop, t->input.width,
2948 t->output.height, t->output.format);
2953 update_offset(t->output.format,
2954 t->output.width, t->output.height,
2955 t->output.crop.pos.x,
2956 t->output.crop.pos.y,
2957 &t->set.o_off, &t->set.o_uoff,
2958 &t->set.o_voff, &t->set.ostride);
2960 dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
2961 t->set.o_off, t->set.o_uoff, t->set.ostride);
2968 dev_err(t->dev, "ERR %s set_crop.\n", __func__);
2973 static void get_res_do_task(struct ipu_task_entry *t)
2976 uint32_t split_child;
2979 found = get_vdoa_ipu_res(t);
2981 dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n",
2985 if (t->set.task & VDOA_ONLY)
2986 do_task_vdoa_only(t);
2987 else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
2988 (t->set.mode & VDOA_BAND_MODE) &&
2989 (t->input.crop.w > soc_max_vdi_in_width()))
2990 do_task_vdoa_vdi(t);
2993 put_vdoa_ipu_res(t, 0);
2995 if (t->state != STATE_OK) {
2996 dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
2997 t, t->task_no, state_msg[t->state].msg);
3000 split_child = need_split(t) && t->parent;
3002 lock = &t->parent->split_lock;
3006 wake_up(&t->parent->split_waitq);
3012 static void wait_split_task_complete(struct ipu_task_entry *parent,
3013 struct ipu_split_task *sp_task, uint32_t size)
3015 struct ipu_task_entry *tsk = NULL;
3018 unsigned long flags;
3019 struct mutex *lock = &parent->split_lock;
3020 int k, busy_vf, busy_pp;
3021 struct ipu_soc *ipu;
3024 for (j = 0; j < size; j++) {
3025 rc = wait_event_timeout(
3026 parent->split_waitq,
3027 sp_task_check_done(sp_task, parent, size, &idx),
3028 msecs_to_jiffies(parent->timeout - DEF_DELAY_MS));
3030 dev_err(parent->dev,
3031 "ERR:[0x%p] no-0x%x, split_task timeout,j:%d,"
3033 parent, parent->task_no, j, size);
3038 dev_err(parent->dev,
3039 "ERR:[0x%p] no-0x%x, invalid task idx:%d\n",
3040 parent, parent->task_no, idx);
3043 tsk = sp_task[idx].child_task;
3045 if (!tsk->split_done || !tsk->ipu)
3047 "ERR:no-0x%x,split not done:%d/null ipu:0x%p\n",
3048 tsk->task_no, tsk->split_done, tsk->ipu);
3049 tsk->split_done = 0;
3053 "[0x%p] no-0x%x sp_tsk[%d] done,state:%d.\n",
3054 tsk, tsk->task_no, idx, tsk->state);
3056 CHECK_PERF(&tsk->ts_rel);
3057 PRINT_TASK_STATISTICS;
3063 if (ret == -ETIMEDOUT) {
3065 for (k = 0; k < max_ipu_no; k++) {
3066 ipu = ipu_get_soc(k);
3068 dev_err(parent->dev, "no:0x%x, null ipu:%d\n",
3069 parent->task_no, k);
3071 busy_vf = ic_vf_pp_is_busy(ipu, true);
3072 busy_pp = ic_vf_pp_is_busy(ipu, false);
3073 dev_err(parent->dev,
3074 "ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
3075 k, busy_vf, busy_pp);
3078 for (k = 0; k < size; k++) {
3079 tsk = sp_task[k].child_task;
3082 dev_err(parent->dev,
3083 "ERR: sp_task[%d][0x%p] no-0x%x done:%d,"
3084 "state:%s,on_list:%d, ipu:0x%p,timeout!\n",
3085 k, tsk, tsk->task_no, tsk->split_done,
3086 state_msg[tsk->state].msg, tsk->task_in_list,
3091 for (j = 0; j < size; j++) {
3092 tsk = sp_task[j].child_task;
3095 spin_lock_irqsave(&ipu_task_list_lock, flags);
3096 if (tsk->task_in_list) {
3097 list_del(&tsk->node);
3098 tsk->task_in_list = 0;
3100 "[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
3101 tsk, tsk->task_no, tsk->task_id);
3103 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3106 if (tsk->state != STATE_OK) {
3108 "ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n",
3109 tsk, tsk->task_no, tsk->task_id,
3110 state_msg[tsk->state].msg);
3112 kref_put(&tsk->refcount, task_mem_free);
3115 kfree(parent->vditmpbuf[0]);
3116 kfree(parent->vditmpbuf[1]);
3119 parent->state = STATE_TIMEOUT;
3121 parent->state = STATE_OK;
3125 static inline int find_task(struct ipu_task_entry **t, int thread_id)
3128 unsigned long flags;
3129 struct ipu_task_entry *tsk;
3130 struct list_head *task_list = &ipu_task_list;
3133 spin_lock_irqsave(&ipu_task_list_lock, flags);
3134 found = !list_empty(task_list);
3136 tsk = list_first_entry(task_list, struct ipu_task_entry, node);
3137 if (tsk->task_in_list) {
3138 list_del(&tsk->node);
3139 tsk->task_in_list = 0;
3141 kref_get(&tsk->refcount);
3143 "thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n",
3144 thread_id, tsk, tsk->task_no, tsk->set.mode);
3147 "thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n",
3148 thread_id, tsk->task_no, tsk->set.mode);
3150 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3155 static int ipu_task_thread(void *argv)
3157 struct ipu_task_entry *tsk;
3158 struct ipu_task_entry *sp_tsk0;
3159 struct ipu_split_task sp_task[4];
3160 /* priority lower than irq_thread */
3161 const struct sched_param param = {
3162 .sched_priority = MAX_USER_RT_PRIO/2 - 1,
3167 unsigned long flags;
3169 struct cpumask cpu_mask;
3170 struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
3173 curr_thread_id = thread_id;
3174 sched_setscheduler(current, SCHED_FIFO, ¶m);
3176 if (!data->is_vdoa) {
3177 cpu = cpumask_first(cpu_online_mask);
3178 cpumask_set_cpu(cpu, &cpu_mask);
3179 ret = sched_setaffinity(data->ipu->thread[data->id]->pid,
3182 pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret);
3184 pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu);
3187 while (!kthread_should_stop()) {
3192 wait_event_interruptible(thread_waitq, find_task(&tsk, curr_thread_id));
3195 pr_err("thread:%d can not find task.\n",
3200 /* note: other threads run split child task */
3201 split_parent = need_split(tsk) && !tsk->parent;
3202 split_child = need_split(tsk) && tsk->parent;
3204 if ((tsk->set.split_mode == RL_SPLIT) ||
3205 (tsk->set.split_mode == UD_SPLIT))
3209 ret = queue_split_task(tsk, sp_task, size);
3213 struct list_head *pos;
3215 spin_lock_irqsave(&ipu_task_list_lock, flags);
3217 sp_tsk0 = list_first_entry(&tsk->split_list,
3218 struct ipu_task_entry, node);
3219 list_del(&sp_tsk0->node);
3221 list_for_each(pos, &tsk->split_list) {
3222 struct ipu_task_entry *tmp;
3224 tmp = list_entry(pos,
3225 struct ipu_task_entry, node);
3226 tmp->task_in_list = 1;
3228 "[0x%p] no-0x%x,id:%d sp_tsk "
3229 "add_to_list.\n", tmp,
3230 tmp->task_no, tmp->task_id);
3232 /* add to global list */
3233 list_splice(&tsk->split_list, &ipu_task_list);
3235 spin_unlock_irqrestore(&ipu_task_list_lock,
3237 /* let the parent thread do the first sp_task */
3238 /* FIXME: ensure the correct sequence for split
3242 "ERR: no-0x%x,can not get split_tsk0\n",
3244 wake_up_interruptible(&thread_waitq);
3245 get_res_do_task(sp_tsk0);
3246 dev_dbg(sp_tsk0->dev,
3247 "thread:%d complete tsk no:0x%x.\n",
3248 curr_thread_id, sp_tsk0->task_no);
3249 ret = atomic_read(&req_cnt);
3251 wake_up(&res_waitq);
3252 dev_dbg(sp_tsk0->dev,
3253 "sp_tsk0 sche thread:%d no:0x%x,"
3254 "req_cnt:%d\n", curr_thread_id,
3255 sp_tsk0->task_no, ret);
3256 /* For other threads to get_res */
3261 get_res_do_task(tsk);
3263 /* wait for all 4 sp_task finished here or timeout
3264 and then release all resources */
3265 if (split_parent && !split_fail)
3266 wait_split_task_complete(tsk, sp_task, size);
3269 atomic_inc(&tsk->done);
3270 wake_up(&tsk->task_waitq);
3273 dev_dbg(tsk->dev, "thread:%d complete tsk no:0x%x-[0x%p].\n",
3274 curr_thread_id, tsk->task_no, tsk);
3275 ret = atomic_read(&req_cnt);
3277 wake_up(&res_waitq);
3278 dev_dbg(tsk->dev, "sche thread:%d no:0x%x,req_cnt:%d\n",
3279 curr_thread_id, tsk->task_no, ret);
3280 /* note: give cpu to other threads to get_res */
3284 kref_put(&tsk->refcount, task_mem_free);
3287 pr_info("ERR %s exit.\n", __func__);
3291 int ipu_check_task(struct ipu_task *task)
3293 struct ipu_task_entry *tsk;
3296 tsk = create_task_entry(task);
3298 return PTR_ERR(tsk);
3300 ret = check_task(tsk);
3302 task->input = tsk->input;
3303 task->output = tsk->output;
3304 task->overlay = tsk->overlay;
3305 dump_task_info(tsk);
3307 kref_put(&tsk->refcount, task_mem_free);
3309 pr_debug("%s ret:%d.\n", __func__, ret);
3312 EXPORT_SYMBOL_GPL(ipu_check_task);
3314 int ipu_queue_task(struct ipu_task *task)
3316 struct ipu_task_entry *tsk;
3317 unsigned long flags;
3322 tsk = create_task_entry(task);
3324 return PTR_ERR(tsk);
3326 CHECK_PERF(&tsk->ts_queue);
3327 ret = prepare_task(tsk);
3331 if (need_split(tsk)) {
3332 CHECK_PERF(&tsk->ts_dotask);
3333 CHECK_PERF(&tsk->ts_waitirq);
3334 CHECK_PERF(&tsk->ts_inirq);
3335 CHECK_PERF(&tsk->ts_wakeup);
3338 /* task_no last four bits for split task type*/
3339 tmp_task_no = atomic_inc_return(&frame_no);
3340 tsk->task_no = tmp_task_no << 4;
3341 init_waitqueue_head(&tsk->task_waitq);
3343 spin_lock_irqsave(&ipu_task_list_lock, flags);
3344 list_add_tail(&tsk->node, &ipu_task_list);
3345 tsk->task_in_list = 1;
3346 dev_dbg(tsk->dev, "[0x%p,no-0x%x] list_add_tail\n", tsk, tsk->task_no);
3347 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3348 wake_up_interruptible(&thread_waitq);
3350 ret = wait_event_timeout(tsk->task_waitq, atomic_read(&tsk->done),
3351 msecs_to_jiffies(tsk->timeout));
3353 /* note: the timeout should larger than the internal timeout!*/
3355 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x, timeout:%dms!\n",
3356 tsk, tsk->task_no, tsk->timeout);
3358 if (STATE_OK != tsk->state) {
3359 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x,state %d: %s\n",
3360 tsk, tsk->task_no, tsk->state,
3361 state_msg[tsk->state].msg);
3367 spin_lock_irqsave(&ipu_task_list_lock, flags);
3368 if (tsk->task_in_list) {
3369 list_del(&tsk->node);
3370 tsk->task_in_list = 0;
3371 dev_dbg(tsk->dev, "[0x%p] no:0x%x list_del\n",
3374 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3377 CHECK_PERF(&tsk->ts_rel);
3378 PRINT_TASK_STATISTICS;
3379 if (ts_frame_avg == 0)
3380 ts_frame_avg = ts_frame.tv_nsec / NSEC_PER_USEC +
3381 ts_frame.tv_sec * USEC_PER_SEC;
3383 ts_frame_avg = (ts_frame_avg + ts_frame.tv_nsec / NSEC_PER_USEC
3384 + ts_frame.tv_sec * USEC_PER_SEC)/2;
3385 if (timespec_compare(&ts_frame, &ts_frame_max) > 0)
3386 ts_frame_max = ts_frame;
3388 atomic_inc(&frame_cnt);
3390 if ((atomic_read(&frame_cnt) % 1000) == 0)
3391 pr_debug("ipu_dev: max frame time:%ldus, avg frame time:%dus,"
3392 "frame_cnt:%d\n", ts_frame_max.tv_nsec / NSEC_PER_USEC
3393 + ts_frame_max.tv_sec * USEC_PER_SEC,
3394 ts_frame_avg, atomic_read(&frame_cnt));
3398 dev_err(tsk->dev, "ERR: no-0x%x,ipu_queue_task err:%d\n",
3401 kref_put(&tsk->refcount, task_mem_free);
3405 EXPORT_SYMBOL_GPL(ipu_queue_task);
3407 static int mxc_ipu_open(struct inode *inode, struct file *file)
3409 file->private_data = (void *)atomic_inc_return(&file_index);
3413 static long mxc_ipu_ioctl(struct file *file,
3414 unsigned int cmd, unsigned long arg)
3416 int __user *argp = (void __user *)arg;
3420 case IPU_CHECK_TASK:
3422 struct ipu_task task;
3425 (&task, (struct ipu_task *) arg,
3426 sizeof(struct ipu_task)))
3428 ret = ipu_check_task(&task);
3429 if (copy_to_user((struct ipu_task *) arg,
3430 &task, sizeof(struct ipu_task)))
3434 case IPU_QUEUE_TASK:
3436 struct ipu_task task;
3439 (&task, (struct ipu_task *) arg,
3440 sizeof(struct ipu_task)))
3442 ret = ipu_queue_task(&task);
3448 struct ipu_alloc_list *mem;
3450 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
3454 if (get_user(size, argp))
3457 mem->size = PAGE_ALIGN(size);
3459 mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
3461 GFP_DMA | GFP_KERNEL);
3462 if (mem->cpu_addr == NULL) {
3466 mem->file_index = file->private_data;
3467 mutex_lock(&ipu_alloc_lock);
3468 list_add(&mem->list, &ipu_alloc_list);
3469 mutex_unlock(&ipu_alloc_lock);
3471 dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
3472 mem->size, mem->phy_addr);
3474 if (put_user(mem->phy_addr, argp))
3481 unsigned long offset;
3482 struct ipu_alloc_list *mem;
3484 if (get_user(offset, argp))
3488 mutex_lock(&ipu_alloc_lock);
3489 list_for_each_entry(mem, &ipu_alloc_list, list) {
3490 if (mem->phy_addr == offset) {
3491 list_del(&mem->list);
3492 dma_free_coherent(ipu_dev,
3501 mutex_unlock(&ipu_alloc_lock);
3503 dev_dbg(ipu_dev, "free %d bytes @ 0x%08X\n",
3504 mem->size, mem->phy_addr);
3514 static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
3518 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
3519 struct ipu_alloc_list *mem;
3521 mutex_lock(&ipu_alloc_lock);
3522 list_for_each_entry(mem, &ipu_alloc_list, list) {
3523 if (offset == mem->phy_addr) {
3529 mutex_unlock(&ipu_alloc_lock);
3533 if (vma->vm_end - vma->vm_start > len)
3536 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
3538 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
3539 vma->vm_end - vma->vm_start,
3540 vma->vm_page_prot)) {
3548 static int mxc_ipu_release(struct inode *inode, struct file *file)
3550 struct ipu_alloc_list *mem;
3551 struct ipu_alloc_list *n;
3553 mutex_lock(&ipu_alloc_lock);
3554 list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
3555 if ((mem->cpu_addr != 0) &&
3556 (file->private_data == mem->file_index)) {
3557 list_del(&mem->list);
3558 dma_free_coherent(ipu_dev,
3562 dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
3563 mem->size, mem->phy_addr);
3567 mutex_unlock(&ipu_alloc_lock);
3568 atomic_dec(&file_index);
3573 static struct file_operations mxc_ipu_fops = {
3574 .owner = THIS_MODULE,
3575 .open = mxc_ipu_open,
3576 .mmap = mxc_ipu_mmap,
3577 .release = mxc_ipu_release,
3578 .unlocked_ioctl = mxc_ipu_ioctl,
3581 int register_ipu_device(struct ipu_soc *ipu, int id)
3585 static struct ipu_thread_data thread_data[5];
3588 major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
3590 printk(KERN_ERR "Unable to register mxc_ipu as a char device\n");
3592 goto register_cdev_fail;
3595 ipu_class = class_create(THIS_MODULE, "mxc_ipu");
3596 if (IS_ERR(ipu_class)) {
3597 ret = PTR_ERR(ipu_class);
3598 goto ipu_class_fail;
3601 ipu_dev = device_create(ipu_class, NULL, MKDEV(major, 0),
3603 if (IS_ERR(ipu_dev)) {
3604 ret = PTR_ERR(ipu_dev);
3605 goto dev_create_fail;
3607 ipu_dev->dma_mask = kmalloc(sizeof(*ipu_dev->dma_mask), GFP_KERNEL);
3608 *ipu_dev->dma_mask = DMA_BIT_MASK(32);
3609 ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32);
3611 mutex_init(&ipu_ch_tbl.lock);
3614 ipu->rot_dma[0].size = 0;
3615 ipu->rot_dma[1].size = 0;
3617 thread_data[idx].ipu = ipu;
3618 thread_data[idx].id = 0;
3619 thread_data[idx].is_vdoa = 0;
3620 ipu->thread[0] = kthread_run(ipu_task_thread, &thread_data[idx++],
3622 if (IS_ERR(ipu->thread[0])) {
3623 ret = PTR_ERR(ipu->thread[0]);
3627 thread_data[idx].ipu = ipu;
3628 thread_data[idx].id = 1;
3629 thread_data[idx].is_vdoa = 0;
3630 ipu->thread[1] = kthread_run(ipu_task_thread, &thread_data[idx++],
3632 if (IS_ERR(ipu->thread[1])) {
3633 ret = PTR_ERR(ipu->thread[1]);
3641 kthread_stop(ipu->thread[0]);
3644 device_destroy(ipu_class, MKDEV(major, 0));
3647 class_destroy(ipu_class);
3651 unregister_chrdev(major, "mxc_ipu");
3656 void unregister_ipu_device(struct ipu_soc *ipu, int id)
3660 kthread_stop(ipu->thread[0]);
3661 kthread_stop(ipu->thread[1]);
3662 for (i = 0; i < 2; i++) {
3663 if (ipu->rot_dma[i].vaddr)
3664 dma_free_coherent(ipu_dev,
3665 ipu->rot_dma[i].size,
3666 ipu->rot_dma[i].vaddr,
3667 ipu->rot_dma[i].paddr);
3671 device_destroy(ipu_class, MKDEV(major, 0));
3672 class_destroy(ipu_class);
3673 unregister_chrdev(major, "mxc_ipu");