2 * Copyright 2005-2014 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/kernel.h>
30 #include <linux/kthread.h>
31 #include <linux/module.h>
32 #include <linux/platform_device.h>
33 #include <linux/poll.h>
34 #include <linux/sched.h>
35 #include <linux/sched/rt.h>
36 #include <linux/slab.h>
37 #include <linux/spinlock.h>
38 #include <linux/time.h>
39 #include <linux/types.h>
40 #include <linux/vmalloc.h>
41 #include <linux/wait.h>
43 #include <asm/cacheflush.h>
44 #include <asm/outercache.h>
46 #include "ipu_param_mem.h"
50 #define CHECK_RETCODE(cont, str, err, label, ret) \
53 dev_err(t->dev, "ERR:[0x%p]-no:0x%x "#str" ret:%d," \
54 "line:%d\n", t, t->task_no, ret, __LINE__);\
55 if (ret != -EACCES) { \
62 #define CHECK_RETCODE_CONT(cont, str, err, ret) \
65 dev_err(t->dev, "ERR:[0x%p]-no:0x%x"#str" ret:%d," \
66 "line:%d\n", t, t->task_no, ret, __LINE__);\
67 if (ret != -EACCES) { \
68 if (t->state == STATE_OK) \
76 #define CHECK_PERF(ts) \
81 #define DECLARE_PERF_VAR \
82 struct timespec ts_queue; \
83 struct timespec ts_dotask; \
84 struct timespec ts_waitirq; \
85 struct timespec ts_sche; \
86 struct timespec ts_rel; \
87 struct timespec ts_frame
89 #define PRINT_TASK_STATISTICS \
91 ts_queue = timespec_sub(tsk->ts_dotask, tsk->ts_queue); \
92 ts_dotask = timespec_sub(tsk->ts_waitirq, tsk->ts_dotask); \
93 ts_waitirq = timespec_sub(tsk->ts_inirq, tsk->ts_waitirq); \
94 ts_sche = timespec_sub(tsk->ts_wakeup, tsk->ts_inirq); \
95 ts_rel = timespec_sub(tsk->ts_rel, tsk->ts_wakeup); \
96 ts_frame = timespec_sub(tsk->ts_rel, tsk->ts_queue); \
97 dev_dbg(tsk->dev, "[0x%p] no-0x%x, ts_q:%ldus, ts_do:%ldus," \
98 "ts_waitirq:%ldus,ts_sche:%ldus, ts_rel:%ldus," \
99 "ts_frame: %ldus\n", tsk, tsk->task_no, \
100 ts_queue.tv_nsec / NSEC_PER_USEC + ts_queue.tv_sec * USEC_PER_SEC,\
101 ts_dotask.tv_nsec / NSEC_PER_USEC + ts_dotask.tv_sec * USEC_PER_SEC,\
102 ts_waitirq.tv_nsec / NSEC_PER_USEC + ts_waitirq.tv_sec * USEC_PER_SEC,\
103 ts_sche.tv_nsec / NSEC_PER_USEC + ts_sche.tv_sec * USEC_PER_SEC,\
104 ts_rel.tv_nsec / NSEC_PER_USEC + ts_rel.tv_sec * USEC_PER_SEC,\
105 ts_frame.tv_nsec / NSEC_PER_USEC + ts_frame.tv_sec * USEC_PER_SEC); \
106 if ((ts_frame.tv_nsec/NSEC_PER_USEC + ts_frame.tv_sec*USEC_PER_SEC) > \
108 dev_dbg(tsk->dev, "ts_frame larger than 80ms [0x%p] no-0x%x.\n"\
109 , tsk, tsk->task_no); \
112 #define CHECK_PERF(ts)
113 #define DECLARE_PERF_VAR
114 #define PRINT_TASK_STATISTICS
117 #define IPU_PP_CH_VF (IPU_TASK_ID_VF - 1)
118 #define IPU_PP_CH_PP (IPU_TASK_ID_PP - 1)
119 #define MAX_PP_CH (IPU_TASK_ID_MAX - 1)
120 #define VDOA_DEF_TIMEOUT_MS (HZ/2)
122 /* Strucutures and variables for exporting MXC IPU as device*/
135 STATE_ENABLE_CHAN_FAIL,
136 STATE_DISABLE_CHAN_FAIL,
138 STATE_INIT_CHAN_FAIL,
139 STATE_LINK_CHAN_FAIL,
140 STATE_UNLINK_CHAN_FAIL,
141 STATE_INIT_CHAN_BUF_FAIL,
142 STATE_INIT_CHAN_BAND_FAIL,
144 STATE_VDOA_IRQ_TIMEOUT,
146 STATE_VDOA_TASK_FAIL,
150 INPUT_CHAN_VDI_P = 1,
155 struct ipu_state_msg {
160 {STATE_QUEUE, "split queue"},
161 {STATE_IN_PROGRESS, "split in progress"},
162 {STATE_ERR, "error"},
163 {STATE_TIMEOUT, "split task timeout"},
164 {STATE_RES_TIMEOUT, "wait resource timeout"},
165 {STATE_NO_IPU, "no ipu found"},
166 {STATE_NO_IRQ, "no irq found for task"},
167 {STATE_IPU_BUSY, "ipu busy"},
168 {STATE_IRQ_FAIL, "request irq failed"},
169 {STATE_IRQ_TIMEOUT, "wait for irq timeout"},
170 {STATE_ENABLE_CHAN_FAIL, "ipu enable channel fail"},
171 {STATE_DISABLE_CHAN_FAIL, "ipu disable channel fail"},
172 {STATE_SEL_BUF_FAIL, "ipu select buf fail"},
173 {STATE_INIT_CHAN_FAIL, "ipu init channel fail"},
174 {STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
175 {STATE_UNLINK_CHAN_FAIL, "ipu unlink channel fail"},
176 {STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
177 {STATE_INIT_CHAN_BAND_FAIL, "ipu init channel band mode fail"},
178 {STATE_SYS_NO_MEM, "sys no mem: -ENOMEM"},
179 {STATE_VDOA_IRQ_TIMEOUT, "wait for vdoa irq timeout"},
180 {STATE_VDOA_IRQ_FAIL, "vdoa irq fail"},
181 {STATE_VDOA_TASK_FAIL, "vdoa task fail"},
184 struct stripe_setting {
189 u32 outh_resize_ratio;
190 u32 outv_resize_ratio;
204 #define NULL_MODE 0x0
208 #define IPU_PREPROCESS_MODE_MASK (IC_MODE | ROT_MODE | VDI_MODE)
209 /* VDOA_MODE means this task use vdoa, and VDOA has two modes:
210 * BAND MODE and non-BAND MODE. Non-band mode will do transfer data
211 * to memory. BAND mode needs hareware sync with IPU, it is used default
212 * if connected to VDIC.
214 #define VDOA_MODE 0x8
215 #define VDOA_BAND_MODE 0x10
222 #define VDOA_ONLY 0x20
227 #define LEFT_STRIPE 0x1
228 #define RIGHT_STRIPE 0x2
229 #define UP_STRIPE 0x4
230 #define DOWN_STRIPE 0x8
231 #define SPLIT_MASK 0xF
234 ipu_channel_t ic_chan;
235 ipu_channel_t rot_chan;
236 ipu_channel_t vdi_ic_p_chan;
237 ipu_channel_t vdi_ic_n_chan;
263 struct stripe_setting sp_setting;
266 struct ipu_split_task {
267 struct ipu_task task;
268 struct ipu_task_entry *parent_task;
269 struct ipu_task_entry *child_task;
273 struct ipu_task_entry {
274 struct ipu_input input;
275 struct ipu_output output;
278 struct ipu_overlay overlay;
279 #define DEF_TIMEOUT_MS 1000
280 #define DEF_DELAY_MS 20
288 struct mutex split_lock;
289 struct mutex vdic_lock;
290 wait_queue_head_t split_waitq;
292 struct list_head node;
293 struct list_head split_list;
297 wait_queue_head_t task_waitq;
298 struct completion irq_comp;
299 struct kref refcount;
306 struct ipu_task_entry *parent;
313 vdoa_handle_t vdoa_handle;
314 struct vdoa_output_mem {
321 struct timespec ts_queue;
322 struct timespec ts_dotask;
323 struct timespec ts_waitirq;
324 struct timespec ts_inirq;
325 struct timespec ts_wakeup;
326 struct timespec ts_rel;
330 struct ipu_channel_tabel {
332 u8 used[MXC_IPU_MAX_NUM][MAX_PP_CH];
336 struct ipu_thread_data {
342 struct ipu_alloc_list {
343 struct list_head list;
350 static LIST_HEAD(ipu_alloc_list);
351 static DEFINE_MUTEX(ipu_alloc_lock);
352 static struct ipu_channel_tabel ipu_ch_tbl;
353 static LIST_HEAD(ipu_task_list);
354 static DEFINE_SPINLOCK(ipu_task_list_lock);
355 static DECLARE_WAIT_QUEUE_HEAD(thread_waitq);
356 static DECLARE_WAIT_QUEUE_HEAD(res_waitq);
357 static atomic_t req_cnt;
358 static atomic_t file_index = ATOMIC_INIT(1);
360 static int max_ipu_no;
361 static int thread_id;
362 static atomic_t frame_no;
363 static struct class *ipu_class;
364 static struct device *ipu_dev;
366 module_param(debug, int, 0600);
368 static struct timespec ts_frame_max;
369 static u32 ts_frame_avg;
370 static atomic_t frame_cnt;
373 static bool deinterlace_3_field(struct ipu_task_entry *t)
375 return ((t->set.mode & VDI_MODE) &&
376 (t->input.deinterlace.motion != HIGH_MOTION));
379 static u32 tiled_filed_size(struct ipu_task_entry *t)
383 /* note: page_align is required by VPU hw ouput buffer */
384 field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2);
388 static bool only_ic(u8 mode)
390 mode = mode & IPU_PREPROCESS_MODE_MASK;
391 return ((mode == IC_MODE) || (mode == VDI_MODE));
394 static bool only_rot(u8 mode)
396 mode = mode & IPU_PREPROCESS_MODE_MASK;
397 return (mode == ROT_MODE);
400 static bool ic_and_rot(u8 mode)
402 mode = mode & IPU_PREPROCESS_MODE_MASK;
403 return ((mode == (IC_MODE | ROT_MODE)) ||
404 (mode == (VDI_MODE | ROT_MODE)));
407 static bool need_split(struct ipu_task_entry *t)
409 return ((t->set.split_mode != NO_SPLIT) || (t->task_no & SPLIT_MASK));
412 unsigned int fmt_to_bpp(unsigned int pixelformat)
416 switch (pixelformat) {
417 case IPU_PIX_FMT_RGB565:
419 case IPU_PIX_FMT_YUYV:
420 case IPU_PIX_FMT_UYVY:
421 /*non-interleaved 422*/
422 case IPU_PIX_FMT_YUV422P:
423 case IPU_PIX_FMT_YVU422P:
426 case IPU_PIX_FMT_BGR24:
427 case IPU_PIX_FMT_RGB24:
428 case IPU_PIX_FMT_YUV444:
429 case IPU_PIX_FMT_YUV444P:
432 case IPU_PIX_FMT_BGR32:
433 case IPU_PIX_FMT_BGRA32:
434 case IPU_PIX_FMT_RGB32:
435 case IPU_PIX_FMT_RGBA32:
436 case IPU_PIX_FMT_ABGR32:
439 /*non-interleaved 420*/
440 case IPU_PIX_FMT_YUV420P:
441 case IPU_PIX_FMT_YVU420P:
442 case IPU_PIX_FMT_YUV420P2:
443 case IPU_PIX_FMT_NV12:
452 EXPORT_SYMBOL_GPL(fmt_to_bpp);
454 cs_t colorspaceofpixel(int fmt)
457 case IPU_PIX_FMT_RGB565:
458 case IPU_PIX_FMT_BGR24:
459 case IPU_PIX_FMT_RGB24:
460 case IPU_PIX_FMT_BGRA32:
461 case IPU_PIX_FMT_BGR32:
462 case IPU_PIX_FMT_RGBA32:
463 case IPU_PIX_FMT_RGB32:
464 case IPU_PIX_FMT_ABGR32:
467 case IPU_PIX_FMT_UYVY:
468 case IPU_PIX_FMT_YUYV:
469 case IPU_PIX_FMT_YUV420P2:
470 case IPU_PIX_FMT_YUV420P:
471 case IPU_PIX_FMT_YVU420P:
472 case IPU_PIX_FMT_YVU422P:
473 case IPU_PIX_FMT_YUV422P:
474 case IPU_PIX_FMT_YUV444:
475 case IPU_PIX_FMT_YUV444P:
476 case IPU_PIX_FMT_NV12:
477 case IPU_PIX_FMT_TILED_NV12:
478 case IPU_PIX_FMT_TILED_NV12F:
485 EXPORT_SYMBOL_GPL(colorspaceofpixel);
487 int need_csc(int ifmt, int ofmt)
491 ics = colorspaceofpixel(ifmt);
492 ocs = colorspaceofpixel(ofmt);
494 if ((ics == NULL_CS) || (ocs == NULL_CS))
501 EXPORT_SYMBOL_GPL(need_csc);
503 static int soc_max_in_width(u32 is_vdoa)
505 return is_vdoa ? 8192 : 4096;
508 static int soc_max_vdi_in_width(void)
510 return IPU_MAX_VDI_IN_WIDTH;
512 static int soc_max_in_height(void)
517 static int soc_max_out_width(void)
519 /* mx51/mx53/mx6q is 1024*/
523 static int soc_max_out_height(void)
525 /* mx51/mx53/mx6q is 1024*/
529 static void dump_task_info(struct ipu_task_entry *t)
533 dev_dbg(t->dev, "[0x%p]input:\n", (void *)t);
534 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format);
535 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width);
536 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height);
537 dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w);
538 dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h);
539 dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
540 (void *)t, t->input.crop.pos.x);
541 dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
542 (void *)t, t->input.crop.pos.y);
543 dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t);
544 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr);
545 dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off);
546 dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff);
547 dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff);
548 dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride);
549 if (t->input.deinterlace.enable) {
550 dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t);
551 if (t->input.deinterlace.motion != HIGH_MOTION) {
552 dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t);
553 dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n",
554 (void *)t, t->input.paddr_n);
556 dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t);
559 dev_dbg(t->dev, "[0x%p]output:\n", (void *)t);
560 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format);
561 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width);
562 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height);
563 dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w);
564 dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h);
565 dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
566 (void *)t, t->output.crop.pos.x);
567 dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
568 (void *)t, t->output.crop.pos.y);
569 dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate);
570 dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t);
571 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr);
572 dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off);
573 dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff);
574 dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff);
575 dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride);
578 dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t);
579 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n",
580 (void *)t, t->overlay.format);
581 dev_dbg(t->dev, "[0x%p]\twidth = %d\n",
582 (void *)t, t->overlay.width);
583 dev_dbg(t->dev, "[0x%p]\theight = %d\n",
584 (void *)t, t->overlay.height);
585 dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n",
586 (void *)t, t->overlay.crop.w);
587 dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n",
588 (void *)t, t->overlay.crop.h);
589 dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
590 (void *)t, t->overlay.crop.pos.x);
591 dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
592 (void *)t, t->overlay.crop.pos.y);
593 dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t);
594 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
595 (void *)t, t->overlay.paddr);
596 dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n",
597 (void *)t, t->set.ov_off);
598 dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n",
599 (void *)t, t->set.ov_uoff);
600 dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n",
601 (void *)t, t->set.ov_voff);
602 dev_dbg(t->dev, "[0x%p]\tovstride = %d\n",
603 (void *)t, t->set.ovstride);
604 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
605 dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n",
607 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
608 (void *)t, t->overlay.alpha.loc_alp_paddr);
609 dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n",
610 (void *)t, t->set.ov_alpha_off);
611 dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n",
612 (void *)t, t->set.ov_alpha_stride);
614 dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n",
615 (void *)t, t->overlay.alpha.gvalue);
616 if (t->overlay.colorkey.enable)
617 dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n",
618 (void *)t, t->overlay.colorkey.value);
621 dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id);
622 dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n",
623 (void *)t, t->set.mode);
624 dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE);
625 dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE);
626 dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE);
627 dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no);
630 static void dump_check_err(struct device *dev, int err)
633 case IPU_CHECK_ERR_INPUT_CROP:
634 dev_err(dev, "input crop setting error\n");
636 case IPU_CHECK_ERR_OUTPUT_CROP:
637 dev_err(dev, "output crop setting error\n");
639 case IPU_CHECK_ERR_OVERLAY_CROP:
640 dev_err(dev, "overlay crop setting error\n");
642 case IPU_CHECK_ERR_INPUT_OVER_LIMIT:
643 dev_err(dev, "input over limitation\n");
645 case IPU_CHECK_ERR_OVERLAY_WITH_VDI:
646 dev_err(dev, "do not support overlay with deinterlace\n");
648 case IPU_CHECK_ERR_OV_OUT_NO_FIT:
650 "width/height of overlay and ic output should be same\n");
652 case IPU_CHECK_ERR_PROC_NO_NEED:
653 dev_err(dev, "no ipu processing need\n");
655 case IPU_CHECK_ERR_SPLIT_INPUTW_OVER:
656 dev_err(dev, "split mode input width overflow\n");
658 case IPU_CHECK_ERR_SPLIT_INPUTH_OVER:
659 dev_err(dev, "split mode input height overflow\n");
661 case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER:
662 dev_err(dev, "split mode output width overflow\n");
664 case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER:
665 dev_err(dev, "split mode output height overflow\n");
667 case IPU_CHECK_ERR_SPLIT_WITH_ROT:
668 dev_err(dev, "not support split mode with rotation\n");
670 case IPU_CHECK_ERR_W_DOWNSIZE_OVER:
671 dev_err(dev, "horizontal downsizing ratio overflow\n");
673 case IPU_CHECK_ERR_H_DOWNSIZE_OVER:
674 dev_err(dev, "vertical downsizing ratio overflow\n");
681 static void dump_check_warn(struct device *dev, int warn)
683 if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
684 dev_warn(dev, "input u/v offset not 8 align\n");
685 if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
686 dev_warn(dev, "output u/v offset not 8 align\n");
687 if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
688 dev_warn(dev, "overlay u/v offset not 8 align\n");
691 static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
693 if ((width == 0) || (height == 0)) {
694 pr_err("Invalid param: width=%d, height=%d\n", width, height);
698 if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
699 (IPU_PIX_FMT_TILED_NV12F == fmt)) {
700 if (crop->w || crop->h) {
701 if (((crop->w + crop->pos.x) > width)
702 || ((crop->h + crop->pos.y) > height)
703 || (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
704 || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
705 || (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
706 || (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
708 pr_err("set_crop error MB align.\n");
716 if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
717 || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
718 pr_err("set_crop error w/h MB align.\n");
723 if (crop->w || crop->h) {
724 if (((crop->w + crop->pos.x) > (width + 16))
725 || ((crop->h + crop->pos.y) > height + 16)) {
726 pr_err("set_crop error exceeds width/height.\n");
735 crop->w -= crop->w%8;
736 crop->h -= crop->h%8;
739 if ((crop->w == 0) || (crop->h == 0)) {
740 pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
748 static void update_offset(unsigned int fmt,
749 unsigned int width, unsigned int height,
750 unsigned int pos_x, unsigned int pos_y,
751 int *off, int *uoff, int *voff, int *stride)
753 /* NOTE: u v offset should based on start point of off*/
755 case IPU_PIX_FMT_YUV420P2:
756 case IPU_PIX_FMT_YUV420P:
757 *off = pos_y * width + pos_x;
758 *uoff = (width * (height - pos_y) - pos_x)
759 + (width/2) * (pos_y/2) + pos_x/2;
760 /* In case height is odd, round up to even */
761 *voff = *uoff + (width/2) * ((height+1)/2);
763 case IPU_PIX_FMT_YVU420P:
764 *off = pos_y * width + pos_x;
765 *voff = (width * (height - pos_y) - pos_x)
766 + (width/2) * (pos_y/2) + pos_x/2;
767 /* In case height is odd, round up to even */
768 *uoff = *voff + (width/2) * ((height+1)/2);
770 case IPU_PIX_FMT_YVU422P:
771 *off = pos_y * width + pos_x;
772 *voff = (width * (height - pos_y) - pos_x)
773 + (width/2) * pos_y + pos_x/2;
774 *uoff = *voff + (width/2) * height;
776 case IPU_PIX_FMT_YUV422P:
777 *off = pos_y * width + pos_x;
778 *uoff = (width * (height - pos_y) - pos_x)
779 + (width/2) * pos_y + pos_x/2;
780 *voff = *uoff + (width/2) * height;
782 case IPU_PIX_FMT_YUV444P:
783 *off = pos_y * width + pos_x;
784 *uoff = width * height;
785 *voff = width * height * 2;
787 case IPU_PIX_FMT_NV12:
788 *off = pos_y * width + pos_x;
789 *uoff = (width * (height - pos_y) - pos_x)
790 + width * (pos_y/2) + pos_x;
792 case IPU_PIX_FMT_TILED_NV12:
794 * tiled format, progressive:
795 * assuming that line is aligned with MB height (aligned to 16)
796 * offset = line * stride + (pixel / MB_width) * pixels_in_MB
797 * = line * stride + (pixel / 16) * 256
798 * = line * stride + pixel * 16
800 *off = pos_y * width + (pos_x << 4);
801 *uoff = ALIGN(width * height, SZ_4K) + (*off >> 1) - *off;
803 case IPU_PIX_FMT_TILED_NV12F:
805 * tiled format, interlaced:
806 * same as above, only number of pixels in MB is 128,
809 *off = (pos_y >> 1) * width + (pos_x << 3);
810 *uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1) - *off;
813 *off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
816 *stride = width * bytes_per_pixel(fmt);
819 static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
821 struct stripe_param left_stripe;
822 struct stripe_param right_stripe;
823 struct stripe_param up_stripe;
824 struct stripe_param down_stripe;
829 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
830 return IPU_CHECK_ERR_SPLIT_WITH_ROT;
832 iw = t->input.crop.w;
833 ih = t->input.crop.h;
835 ow = t->output.crop.w;
836 oh = t->output.crop.h;
838 memset(&left_stripe, 0, sizeof(left_stripe));
839 memset(&right_stripe, 0, sizeof(right_stripe));
840 memset(&up_stripe, 0, sizeof(up_stripe));
841 memset(&down_stripe, 0, sizeof(down_stripe));
843 if (t->set.split_mode & RL_SPLIT) {
845 * We do want equal strips: initialize stripes in case
846 * calc_stripes returns before actually doing the calculation
848 left_stripe.input_width = iw / 2;
849 left_stripe.output_width = ow / 2;
850 right_stripe.input_column = iw / 2;
851 right_stripe.output_column = ow / 2;
854 max_width = soc_max_vdi_in_width();
856 max_width = soc_max_out_width();
857 ret = ipu_calc_stripes_sizes(iw,
860 (((unsigned long long)1) << 32), /* 32bit for fractional*/
861 1, /* equal stripes */
867 return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
869 dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
871 t->set.sp_setting.iw = left_stripe.input_width;
872 t->set.sp_setting.ow = left_stripe.output_width;
873 t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
874 t->set.sp_setting.i_left_pos = left_stripe.input_column;
875 t->set.sp_setting.o_left_pos = left_stripe.output_column;
876 t->set.sp_setting.i_right_pos = right_stripe.input_column;
877 t->set.sp_setting.o_right_pos = right_stripe.output_column;
879 t->set.sp_setting.iw = iw;
880 t->set.sp_setting.ow = ow;
881 t->set.sp_setting.outh_resize_ratio = 0;
882 t->set.sp_setting.i_left_pos = 0;
883 t->set.sp_setting.o_left_pos = 0;
884 t->set.sp_setting.i_right_pos = 0;
885 t->set.sp_setting.o_right_pos = 0;
887 if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > (iw+16))
888 return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
889 if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
890 || (t->set.sp_setting.ow > soc_max_out_width()))
891 return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
892 if (rounddown(t->set.sp_setting.ow, 8) * 8 <=
893 rounddown(t->set.sp_setting.iw, 8))
894 return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
896 if (t->set.split_mode & UD_SPLIT) {
898 * We do want equal strips: initialize stripes in case
899 * calc_stripes returns before actually doing the calculation
901 up_stripe.input_width = ih / 2;
902 up_stripe.output_width = oh / 2;
903 down_stripe.input_column = ih / 2;
904 down_stripe.output_column = oh / 2;
905 ret = ipu_calc_stripes_sizes(ih,
907 soc_max_out_height(),
908 (((unsigned long long)1) << 32), /* 32bit for fractional*/
909 0x1 | 0x2, /* equal stripes and vertical */
915 return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
917 dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
919 t->set.sp_setting.ih = up_stripe.input_width;
920 t->set.sp_setting.oh = up_stripe.output_width;
921 t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
922 t->set.sp_setting.i_top_pos = up_stripe.input_column;
923 t->set.sp_setting.o_top_pos = up_stripe.output_column;
924 t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
925 t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
927 t->set.sp_setting.ih = ih;
928 t->set.sp_setting.oh = oh;
929 t->set.sp_setting.outv_resize_ratio = 0;
930 t->set.sp_setting.i_top_pos = 0;
931 t->set.sp_setting.o_top_pos = 0;
932 t->set.sp_setting.i_bottom_pos = 0;
933 t->set.sp_setting.o_bottom_pos = 0;
936 /* downscale case: enforce limits */
937 if (((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > (ih))
938 && (t->set.sp_setting.ih >= t->set.sp_setting.oh))
939 return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
940 /* upscale case: relax limits because ipu_calc_stripes_sizes() may
941 create input stripe that falls just outside of the input window */
942 else if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos)
944 return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
945 if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
946 || (t->set.sp_setting.oh > soc_max_out_height()))
947 return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
948 if (rounddown(t->set.sp_setting.oh, 8) * 8 <=
949 rounddown(t->set.sp_setting.ih, 8))
950 return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
955 static int check_task(struct ipu_task_entry *t)
958 int ret = IPU_CHECK_OK;
960 bool vdi_split = false;
963 if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
964 (IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
965 (IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
966 (IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
967 ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
968 !t->input.deinterlace.enable)) {
969 ret = IPU_CHECK_ERR_NOT_SUPPORT;
974 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
977 ret = IPU_CHECK_ERR_INPUT_CROP;
980 update_offset(t->input.format, t->input.width, t->input.height,
981 t->input.crop.pos.x, t->input.crop.pos.y,
982 &t->set.i_off, &t->set.i_uoff,
983 &t->set.i_voff, &t->set.istride);
986 ret = set_crop(&t->output.crop, t->output.width, t->output.height,
989 ret = IPU_CHECK_ERR_OUTPUT_CROP;
992 update_offset(t->output.format,
993 t->output.width, t->output.height,
994 t->output.crop.pos.x, t->output.crop.pos.y,
995 &t->set.o_off, &t->set.o_uoff,
996 &t->set.o_voff, &t->set.ostride);
998 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1000 * Cache output width and height and
1001 * swap them so that we may check
1002 * downsize overflow correctly.
1004 ocw = t->output.crop.h;
1005 och = t->output.crop.w;
1007 ocw = t->output.crop.w;
1008 och = t->output.crop.h;
1011 if (ocw * 8 <= t->input.crop.w) {
1012 ret = IPU_CHECK_ERR_W_DOWNSIZE_OVER;
1016 if (och * 8 <= t->input.crop.h) {
1017 ret = IPU_CHECK_ERR_H_DOWNSIZE_OVER;
1021 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1022 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1023 if ((t->input.crop.w > soc_max_in_width(1)) ||
1024 (t->input.crop.h > soc_max_in_height())) {
1025 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
1028 /* output fmt: NV12 and YUYV, now don't support resize */
1029 if (((IPU_PIX_FMT_NV12 != t->output.format) &&
1030 (IPU_PIX_FMT_YUYV != t->output.format)) ||
1031 (t->input.crop.w != t->output.crop.w) ||
1032 (t->input.crop.h != t->output.crop.h)) {
1033 ret = IPU_CHECK_ERR_NOT_SUPPORT;
1038 /* check overlay if there is */
1039 if (t->overlay_en) {
1040 if (t->input.deinterlace.enable) {
1041 ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
1045 ret = set_crop(&t->overlay.crop, t->overlay.width,
1046 t->overlay.height, t->overlay.format);
1048 ret = IPU_CHECK_ERR_OVERLAY_CROP;
1051 ocw = t->output.crop.w;
1052 och = t->output.crop.h;
1054 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1055 ocw = t->output.crop.h;
1056 och = t->output.crop.w;
1058 if ((t->overlay.crop.w != ocw) ||
1059 (t->overlay.crop.h != och)) {
1060 ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
1064 update_offset(t->overlay.format,
1065 t->overlay.width, t->overlay.height,
1066 t->overlay.crop.pos.x, t->overlay.crop.pos.y,
1067 &t->set.ov_off, &t->set.ov_uoff,
1068 &t->set.ov_voff, &t->set.ovstride);
1069 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
1070 t->set.ov_alpha_stride = t->overlay.width;
1071 t->set.ov_alpha_off = t->overlay.crop.pos.y *
1072 t->overlay.width + t->overlay.crop.pos.x;
1077 /* input overflow? */
1078 if (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1079 (IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
1080 if ((t->input.crop.w > soc_max_in_width(0)) ||
1081 (t->input.crop.h > soc_max_in_height())) {
1082 ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
1087 /* check task mode */
1088 t->set.mode = NULL_MODE;
1089 t->set.split_mode = NO_SPLIT;
1091 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1093 tmp = t->output.crop.w;
1094 t->output.crop.w = t->output.crop.h;
1095 t->output.crop.h = tmp;
1098 if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
1099 t->set.mode |= ROT_MODE;
1101 /*need resize or CSC?*/
1102 if ((t->input.crop.w != t->output.crop.w) ||
1103 (t->input.crop.h != t->output.crop.h) ||
1104 need_csc(t->input.format, t->output.format))
1105 t->set.mode |= IC_MODE;
1108 if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
1109 t->set.mode |= IC_MODE;
1111 /*need IDMAC do format(same color space)?*/
1112 if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
1113 t->set.mode |= IC_MODE;
1117 t->set.mode |= IC_MODE;
1120 if (t->input.deinterlace.enable) {
1121 t->set.mode &= ~IC_MODE;
1122 t->set.mode |= VDI_MODE;
1124 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
1125 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1126 if (t->set.mode & ROT_MODE) {
1127 ret = IPU_CHECK_ERR_NOT_SUPPORT;
1130 t->set.mode |= VDOA_MODE;
1131 if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
1132 t->set.mode |= VDOA_BAND_MODE;
1133 t->set.mode &= ~IC_MODE;
1136 if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
1137 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
1138 if (t->output.crop.w > soc_max_out_width())
1139 t->set.split_mode |= RL_SPLIT;
1140 if (t->output.crop.h > soc_max_out_height())
1141 t->set.split_mode |= UD_SPLIT;
1142 if (!t->set.split_mode && (t->set.mode & VDI_MODE) &&
1143 (t->input.crop.w > soc_max_vdi_in_width())) {
1144 t->set.split_mode |= RL_SPLIT;
1147 if (t->set.split_mode) {
1148 if ((t->set.split_mode == RL_SPLIT) ||
1149 (t->set.split_mode == UD_SPLIT))
1150 timeout = DEF_TIMEOUT_MS * 2 + DEF_DELAY_MS;
1152 timeout = DEF_TIMEOUT_MS * 4 + DEF_DELAY_MS;
1153 if (t->timeout < timeout)
1154 t->timeout = timeout;
1156 ret = update_split_setting(t, vdi_split);
1157 if (ret > IPU_CHECK_ERR_MIN)
1162 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1164 tmp = t->output.crop.w;
1165 t->output.crop.w = t->output.crop.h;
1166 t->output.crop.h = tmp;
1169 if (t->set.mode == NULL_MODE) {
1170 ret = IPU_CHECK_ERR_PROC_NO_NEED;
1174 if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
1175 ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
1176 if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
1177 ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
1178 if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
1179 ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
1184 if (ret > IPU_CHECK_ERR_MIN)
1185 dump_check_err(t->dev, ret);
1186 else if (ret != IPU_CHECK_OK)
1187 dump_check_warn(t->dev, ret);
1193 static int prepare_task(struct ipu_task_entry *t)
1197 ret = check_task(t);
1198 if (ret > IPU_CHECK_ERR_MIN)
1201 if (t->set.mode & VDI_MODE) {
1202 t->task_id = IPU_TASK_ID_VF;
1203 t->set.task = VDI_VF;
1204 if (t->set.mode & ROT_MODE)
1205 t->set.task |= ROT_VF;
1208 if (VDOA_MODE == t->set.mode) {
1209 if (t->set.task != 0) {
1210 dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
1214 t->set.task |= VDOA_ONLY;
1217 if (VDOA_BAND_MODE & t->set.mode) {
1218 /* to save band size: 1<<3 = 8 lines */
1219 t->set.band_lines = 3;
1227 static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
1231 uint32_t status_rot;
1234 status = ipu_channel_status(ipu, MEM_VDI_PRP_VF_MEM);
1235 status_vf = ipu_channel_status(ipu, MEM_PRP_VF_MEM);
1236 status_rot = ipu_channel_status(ipu, MEM_ROT_VF_MEM);
1237 return status || status_vf || status_rot;
1239 status = ipu_channel_status(ipu, MEM_PP_MEM);
1240 status_rot = ipu_channel_status(ipu, MEM_ROT_PP_MEM);
1241 return status || status_rot;
1245 static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
1248 struct ipu_soc *ipu;
1250 uint32_t found_ipu = 0;
1251 uint32_t found_vdoa = 0;
1252 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1254 mutex_lock(&tbl->lock);
1255 if (t->set.mode & VDOA_MODE) {
1256 if (NULL != t->vdoa_handle)
1259 found_vdoa = tbl->vdoa_used ? 0 : 1;
1262 vdoa_get_handle(&t->vdoa_handle);
1264 /* first get vdoa->ipu resource sequence */
1266 if (t->set.task & VDOA_ONLY)
1271 for (i = 0; i < max_ipu_no; i++) {
1272 ipu = ipu_get_soc(i);
1274 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1275 t->task_no, found_vdoa, i);
1277 used = &tbl->used[i][IPU_PP_CH_VF];
1278 if (t->set.mode & VDI_MODE) {
1284 } else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1286 t->task_id = IPU_TASK_ID_VF;
1287 if (t->set.mode & IC_MODE)
1288 t->set.task |= IC_VF;
1289 if (t->set.mode & ROT_MODE)
1290 t->set.task |= ROT_VF;
1296 dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n",
1297 t->task_no, found_vdoa, t->set.mode);
1302 for (i = 0; i < max_ipu_no; i++) {
1303 ipu = ipu_get_soc(i);
1305 dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
1306 t->task_no, found_vdoa, i);
1308 if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
1309 used = &tbl->used[i][IPU_PP_CH_PP];
1311 t->task_id = IPU_TASK_ID_PP;
1312 if (t->set.mode & IC_MODE)
1313 t->set.task |= IC_PP;
1314 if (t->set.mode & ROT_MODE)
1315 t->set.task |= ROT_PP;
1328 if (atomic_inc_return(&t->res_get) == 2)
1330 "ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
1331 t->task_no, found_vdoa);
1335 "%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
1336 __func__, t->task_no, found_vdoa, found_ipu);
1337 mutex_unlock(&tbl->lock);
1338 if (t->set.task & VDOA_ONLY)
1340 else if (t->set.mode & VDOA_MODE)
1341 return found_vdoa && found_ipu;
1346 static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
1349 int rel_vdoa = 0, rel_ipu = 0;
1350 struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
1352 mutex_lock(&tbl->lock);
1353 if (tsk->set.mode & VDOA_MODE) {
1354 if (!tbl->vdoa_used && tsk->vdoa_handle)
1356 "ERR no:0x%x,vdoa not used,mode:0x%x\n",
1357 tsk->task_no, tsk->set.mode);
1358 if (tbl->vdoa_used && tsk->vdoa_handle) {
1360 vdoa_put_handle(&tsk->vdoa_handle);
1362 tsk->ipu->vdoa_en = 0;
1364 if (vdoa_only || (tsk->set.task & VDOA_ONLY))
1369 tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
1371 ret = atomic_inc_return(&tsk->res_free);
1374 "ERR no:0x%x,rel_vdoa:%d,put ipu twice\n",
1375 tsk->task_no, rel_vdoa);
1378 "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
1379 __func__, tsk->task_no, rel_vdoa, rel_ipu);
1380 mutex_unlock(&tbl->lock);
1383 static int get_vdoa_ipu_res(struct ipu_task_entry *t)
1388 found = _get_vdoa_ipu_res(t);
1392 /* blocking to get resource */
1393 ret = atomic_inc_return(&req_cnt);
1395 "wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
1396 ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
1397 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
1399 dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
1400 t, t->task_no, t->timeout - DEF_DELAY_MS);
1402 t->state = STATE_RES_TIMEOUT;
1405 if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
1407 "ERR[no-0x%x] can not get ipu!\n",
1409 ret = atomic_read(&req_cnt);
1411 ret = atomic_dec_return(&req_cnt);
1414 "ERR[no-0x%x] req_cnt:%d mismatch!\n",
1416 dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n",
1417 t->task_no, t, ret);
1426 static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
1428 struct ipu_task_entry *tsk;
1430 tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
1432 return ERR_PTR(-ENOMEM);
1433 kref_init(&tsk->refcount);
1434 tsk->state = -EINVAL;
1437 tsk->input = task->input;
1438 tsk->output = task->output;
1439 tsk->overlay_en = task->overlay_en;
1440 if (tsk->overlay_en)
1441 tsk->overlay = task->overlay;
1442 if (task->timeout > DEF_TIMEOUT_MS)
1443 tsk->timeout = task->timeout;
1445 tsk->timeout = DEF_TIMEOUT_MS;
1450 static void task_mem_free(struct kref *ref)
1452 struct ipu_task_entry *tsk =
1453 container_of(ref, struct ipu_task_entry, refcount);
1457 int create_split_child_task(struct ipu_split_task *sp_task)
1460 struct ipu_task_entry *tsk;
1462 tsk = create_task_entry(&sp_task->task);
1464 return PTR_ERR(tsk);
1466 sp_task->child_task = tsk;
1467 tsk->task_no = sp_task->task_no;
1469 ret = prepare_task(tsk);
1473 tsk->parent = sp_task->parent_task;
1474 tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
1476 list_add(&tsk->node, &tsk->parent->split_list);
1477 dev_dbg(tsk->dev, "[0x%p] sp_tsk Q list,no-0x%x\n", tsk, tsk->task_no);
1478 tsk->state = STATE_QUEUE;
1479 CHECK_PERF(&tsk->ts_queue);
1484 static inline int sp_task_check_done(struct ipu_split_task *sp_task,
1485 struct ipu_task_entry *parent, int num, int *idx)
1489 struct ipu_task_entry *tsk;
1490 struct mutex *lock = &parent->split_lock;
1494 for (i = 0; i < num; i++) {
1495 tsk = sp_task[i].child_task;
1496 if (tsk && tsk->split_done) {
1508 static int create_split_task(
1510 struct ipu_split_task *sp_task)
1512 struct ipu_task *task = &(sp_task->task);
1513 struct ipu_task_entry *t = sp_task->parent_task;
1516 sp_task->task_no |= stripe;
1518 task->input = t->input;
1519 task->output = t->output;
1520 task->overlay_en = t->overlay_en;
1521 if (task->overlay_en)
1522 task->overlay = t->overlay;
1523 task->task_id = t->task_id;
1524 if ((t->set.split_mode == RL_SPLIT) ||
1525 (t->set.split_mode == UD_SPLIT))
1526 task->timeout = t->timeout / 2;
1528 task->timeout = t->timeout / 4;
1530 task->input.crop.w = t->set.sp_setting.iw;
1531 task->input.crop.h = t->set.sp_setting.ih;
1532 if (task->overlay_en) {
1533 task->overlay.crop.w = t->set.sp_setting.ow;
1534 task->overlay.crop.h = t->set.sp_setting.oh;
1536 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
1537 task->output.crop.w = t->set.sp_setting.oh;
1538 task->output.crop.h = t->set.sp_setting.ow;
1539 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos;
1540 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos;
1543 task->output.crop.w = t->set.sp_setting.ow;
1544 task->output.crop.h = t->set.sp_setting.oh;
1545 t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos;
1546 t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos;
1549 if (stripe & LEFT_STRIPE)
1550 task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
1551 else if (stripe & RIGHT_STRIPE)
1552 task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
1553 if (stripe & UP_STRIPE)
1554 task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
1555 else if (stripe & DOWN_STRIPE)
1556 task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
1558 if (task->overlay_en) {
1559 if (stripe & LEFT_STRIPE)
1560 task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
1561 else if (stripe & RIGHT_STRIPE)
1562 task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
1563 if (stripe & UP_STRIPE)
1564 task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
1565 else if (stripe & DOWN_STRIPE)
1566 task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1569 switch (t->output.rotate) {
1570 case IPU_ROTATE_NONE:
1571 if (stripe & LEFT_STRIPE)
1572 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1573 else if (stripe & RIGHT_STRIPE)
1574 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1575 if (stripe & UP_STRIPE)
1576 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1577 else if (stripe & DOWN_STRIPE)
1578 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1580 case IPU_ROTATE_VERT_FLIP:
1581 if (stripe & LEFT_STRIPE)
1582 task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
1583 else if (stripe & RIGHT_STRIPE)
1584 task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
1585 if (stripe & UP_STRIPE)
1586 task->output.crop.pos.y =
1587 t->output.crop.pos.y + t->output.crop.h
1588 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1589 else if (stripe & DOWN_STRIPE)
1590 task->output.crop.pos.y =
1591 t->output.crop.pos.y + t->output.crop.h
1592 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1594 case IPU_ROTATE_HORIZ_FLIP:
1595 if (stripe & LEFT_STRIPE)
1596 task->output.crop.pos.x =
1597 t->output.crop.pos.x + t->output.crop.w
1598 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1599 else if (stripe & RIGHT_STRIPE)
1600 task->output.crop.pos.x =
1601 t->output.crop.pos.x + t->output.crop.w
1602 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1603 if (stripe & UP_STRIPE)
1604 task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
1605 else if (stripe & DOWN_STRIPE)
1606 task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
1608 case IPU_ROTATE_180:
1609 if (stripe & LEFT_STRIPE)
1610 task->output.crop.pos.x =
1611 t->output.crop.pos.x + t->output.crop.w
1612 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1613 else if (stripe & RIGHT_STRIPE)
1614 task->output.crop.pos.x =
1615 t->output.crop.pos.x + t->output.crop.w
1616 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1617 if (stripe & UP_STRIPE)
1618 task->output.crop.pos.y =
1619 t->output.crop.pos.y + t->output.crop.h
1620 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1621 else if (stripe & DOWN_STRIPE)
1622 task->output.crop.pos.y =
1623 t->output.crop.pos.y + t->output.crop.h
1624 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1626 case IPU_ROTATE_90_RIGHT:
1627 if (stripe & UP_STRIPE)
1628 task->output.crop.pos.x =
1629 t->output.crop.pos.x + t->output.crop.w
1630 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1631 else if (stripe & DOWN_STRIPE)
1632 task->output.crop.pos.x =
1633 t->output.crop.pos.x + t->output.crop.w
1634 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1635 if (stripe & LEFT_STRIPE)
1636 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1637 else if (stripe & RIGHT_STRIPE)
1638 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1640 case IPU_ROTATE_90_RIGHT_HFLIP:
1641 if (stripe & UP_STRIPE)
1642 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1643 else if (stripe & DOWN_STRIPE)
1644 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1645 if (stripe & LEFT_STRIPE)
1646 task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
1647 else if (stripe & RIGHT_STRIPE)
1648 task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
1650 case IPU_ROTATE_90_RIGHT_VFLIP:
1651 if (stripe & UP_STRIPE)
1652 task->output.crop.pos.x =
1653 t->output.crop.pos.x + t->output.crop.w
1654 - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
1655 else if (stripe & DOWN_STRIPE)
1656 task->output.crop.pos.x =
1657 t->output.crop.pos.x + t->output.crop.w
1658 - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
1659 if (stripe & LEFT_STRIPE)
1660 task->output.crop.pos.y =
1661 t->output.crop.pos.y + t->output.crop.h
1662 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1663 else if (stripe & RIGHT_STRIPE)
1664 task->output.crop.pos.y =
1665 t->output.crop.pos.y + t->output.crop.h
1666 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1668 case IPU_ROTATE_90_LEFT:
1669 if (stripe & UP_STRIPE)
1670 task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
1671 else if (stripe & DOWN_STRIPE)
1672 task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
1673 if (stripe & LEFT_STRIPE)
1674 task->output.crop.pos.y =
1675 t->output.crop.pos.y + t->output.crop.h
1676 - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
1677 else if (stripe & RIGHT_STRIPE)
1678 task->output.crop.pos.y =
1679 t->output.crop.pos.y + t->output.crop.h
1680 - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
1683 dev_err(t->dev, "ERR:should not be here\n");
1687 ret = create_split_child_task(sp_task);
1689 dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
1693 static int queue_split_task(struct ipu_task_entry *t,
1694 struct ipu_split_task *sp_task, uint32_t size)
1699 struct ipu_task_entry *tsk = NULL;
1700 struct mutex *lock = &t->split_lock;
1701 struct mutex *vdic_lock = &t->vdic_lock;
1703 dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
1704 t, t->task_no, size);
1706 mutex_init(vdic_lock);
1707 init_waitqueue_head(&t->split_waitq);
1708 INIT_LIST_HEAD(&t->split_list);
1709 for (j = 0; j < size; j++) {
1710 memset(&sp_task[j], 0, sizeof(*sp_task));
1711 sp_task[j].parent_task = t;
1712 sp_task[j].task_no = t->task_no;
1715 if (t->set.split_mode == RL_SPLIT) {
1717 err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
1721 err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
1722 } else if (t->set.split_mode == UD_SPLIT) {
1724 err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
1728 err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
1731 err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1735 err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1739 err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
1743 err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
1747 for (j = 0; j < (i + 1); j++) {
1749 if (sp_task[j].child_task)
1751 "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
1752 j, sp_task[j].child_task->task_no,
1753 sp_task[j].child_task->state, err[j]);
1756 dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
1757 sp_task[j].child_task, j, sp_task[j].child_task->task_no,
1758 state_msg[sp_task[j].child_task->state].msg, err[j]);
1764 for (j = 0; j < (i + 1); j++) {
1765 if (err[j] < 0 && !ret)
1767 tsk = sp_task[j].child_task;
1772 t->state = STATE_ERR;
1777 static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
1778 ipu_channel_t channel, uint32_t ch_type)
1783 dma_addr_t inbuf_base = 0;
1785 struct vdoa_params param;
1786 struct vdoa_ipu_buf buf;
1787 struct ipu_soc *ipu_idx;
1788 u32 ipu_stride, obuf_size;
1792 if ((IPU_PIX_FMT_YUYV != t->output.format) &&
1793 (IPU_PIX_FMT_NV12 != t->output.format)) {
1794 dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
1798 memset(¶m, 0, sizeof(param));
1799 /* init channel tiled bufs */
1800 if (deinterlace_3_field(t) &&
1801 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
1802 field_size = tiled_filed_size(t);
1803 if (INPUT_CHAN_VDI_P == ch_type) {
1804 inbuf_base = t->input.paddr + field_size;
1805 param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
1806 } else if (INPUT_CHAN == ch_type) {
1807 inbuf_base = t->input.paddr_n;
1808 param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
1809 } else if (INPUT_CHAN_VDI_N == ch_type) {
1810 inbuf_base = t->input.paddr_n + field_size;
1811 param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
1814 height = t->input.crop.h >> 1; /* field format for vdoa */
1815 width = t->input.crop.w;
1816 param.vfield_buf.vubo = t->set.i_uoff;
1817 param.interlaced = 1;
1818 param.scan_order = 1;
1819 type = IPU_INPUT_BUFFER;
1820 } else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
1821 (INPUT_CHAN == ch_type)) {
1822 height = t->input.crop.h;
1823 width = t->input.crop.w;
1824 param.vframe_buf.veba = t->input.paddr + t->set.i_off;
1825 param.vframe_buf.vubo = t->set.i_uoff;
1826 type = IPU_INPUT_BUFFER;
1830 param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
1831 if (param.band_mode && (t->set.band_lines != 3) &&
1832 (t->set.band_lines != 4) && (t->set.band_lines != 5))
1834 else if (param.band_mode)
1835 param.band_lines = (1 << t->set.band_lines);
1836 for (i = 0; i < max_ipu_no; i++) {
1837 ipu_idx = ipu_get_soc(i);
1838 if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
1841 if (t->set.task & VDOA_ONLY)
1842 /* dummy, didn't need ipu res */
1844 if (max_ipu_no == i) {
1845 dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
1850 param.vpu_stride = t->input.width;
1851 param.height = height;
1852 param.width = width;
1853 if (IPU_PIX_FMT_NV12 == t->output.format)
1854 param.pfs = VDOA_PFS_NV12;
1856 param.pfs = VDOA_PFS_YUYV;
1857 ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
1859 ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
1860 obuf_size = PAGE_ALIGN(param.width * param.height *
1861 fmt_to_bpp(ipu_fmt)/8);
1862 dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
1863 param.band_mode, param.band_lines);
1864 if (!param.band_mode) {
1865 /* note: if only for tiled -> raster convert and
1866 no other post-processing, we don't need alloc buf
1867 and use output buffer directly.
1869 if (t->set.task & VDOA_ONLY)
1870 param.ieba0 = t->output.paddr;
1872 dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
1876 if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
1877 dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
1881 ret = vdoa_setup(t->vdoa_handle, ¶m);
1884 vdoa_get_output_buf(t->vdoa_handle, &buf);
1885 if (t->set.task & VDOA_ONLY)
1888 ret = ipu_init_channel_buffer(ipu,
1902 t->state = STATE_INIT_CHAN_BUF_FAIL;
1906 if (param.band_mode) {
1907 ret = ipu_set_channel_bandmode(ipu, channel,
1908 type, t->set.band_lines);
1910 t->state = STATE_INIT_CHAN_BAND_FAIL;
1918 static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
1922 if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
1923 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1924 CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
1925 } else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
1926 ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
1927 CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
1928 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
1930 CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
1931 ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
1933 CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
1936 dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n",
1937 t->task_no, t->input.format);
1944 static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
1947 ipu_channel_params_t params;
1948 dma_addr_t inbuf = 0, ovbuf = 0, ov_alp_buf = 0;
1949 dma_addr_t inbuf_p = 0, inbuf_n = 0;
1950 dma_addr_t outbuf = 0;
1951 int out_uoff = 0, out_voff = 0, out_rot;
1952 int out_w = 0, out_h = 0, out_stride;
1954 u32 vdi_frame_idx = 0;
1956 memset(¶ms, 0, sizeof(params));
1958 /* is it need link a rot channel */
1959 if (ic_and_rot(t->set.mode)) {
1960 outbuf = t->set.r_paddr;
1961 out_w = t->set.r_width;
1962 out_h = t->set.r_height;
1963 out_stride = t->set.r_stride;
1964 out_fmt = t->set.r_fmt;
1967 out_rot = IPU_ROTATE_NONE;
1969 outbuf = t->output.paddr + t->set.o_off;
1970 out_w = t->output.crop.w;
1971 out_h = t->output.crop.h;
1972 out_stride = t->set.ostride;
1973 out_fmt = t->output.format;
1974 out_uoff = t->set.o_uoff;
1975 out_voff = t->set.o_voff;
1976 out_rot = t->output.rotate;
1980 params.mem_prp_vf_mem.in_width = t->input.crop.w;
1981 params.mem_prp_vf_mem.out_width = out_w;
1982 params.mem_prp_vf_mem.in_height = t->input.crop.h;
1983 params.mem_prp_vf_mem.out_height = out_h;
1984 params.mem_prp_vf_mem.in_pixel_fmt = t->input.format;
1985 params.mem_prp_vf_mem.out_pixel_fmt = out_fmt;
1986 params.mem_prp_vf_mem.motion_sel = t->input.deinterlace.motion;
1988 params.mem_prp_vf_mem.outh_resize_ratio =
1989 t->set.sp_setting.outh_resize_ratio;
1990 params.mem_prp_vf_mem.outv_resize_ratio =
1991 t->set.sp_setting.outv_resize_ratio;
1993 if (t->overlay_en) {
1994 params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
1995 params.mem_prp_vf_mem.graphics_combine_en = 1;
1996 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
1997 params.mem_prp_vf_mem.global_alpha_en = 1;
1998 else if (t->overlay.alpha.loc_alp_paddr)
1999 params.mem_prp_vf_mem.alpha_chan_en = 1;
2000 /* otherwise, alpha bending per pixel is used. */
2001 params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
2002 if (t->overlay.colorkey.enable) {
2003 params.mem_prp_vf_mem.key_color_en = 1;
2004 params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
2008 if (t->input.deinterlace.enable) {
2009 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_FIELD_MASK)
2010 params.mem_prp_vf_mem.field_fmt =
2011 IPU_DEINTERLACE_FIELD_BOTTOM;
2013 params.mem_prp_vf_mem.field_fmt =
2014 IPU_DEINTERLACE_FIELD_TOP;
2016 if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
2017 vdi_frame_idx = t->input.deinterlace.field_fmt &
2018 IPU_DEINTERLACE_RATE_FRAME1;
2021 if (t->set.mode & VDOA_MODE)
2025 if (!(t->set.task & VDOA_ONLY)) {
2026 ret = ipu_init_channel(ipu, t->set.ic_chan, ¶ms);
2028 t->state = STATE_INIT_CHAN_FAIL;
2033 if (deinterlace_3_field(t)) {
2034 ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, ¶ms);
2036 t->state = STATE_INIT_CHAN_FAIL;
2039 ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, ¶ms);
2041 t->state = STATE_INIT_CHAN_FAIL;
2046 /* init channel bufs */
2047 if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
2048 (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
2049 ret = init_tiled_ch_bufs(ipu, t);
2053 if ((deinterlace_3_field(t)) &&
2054 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2055 if (params.mem_prp_vf_mem.field_fmt ==
2056 IPU_DEINTERLACE_FIELD_TOP) {
2057 if (vdi_frame_idx) {
2058 inbuf_p = t->input.paddr + t->set.istride +
2060 inbuf = t->input.paddr_n + t->set.i_off;
2061 inbuf_n = t->input.paddr_n + t->set.istride +
2063 params.mem_prp_vf_mem.field_fmt =
2064 IPU_DEINTERLACE_FIELD_BOTTOM;
2066 inbuf_p = t->input.paddr + t->set.i_off;
2067 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2068 inbuf_n = t->input.paddr_n + t->set.i_off;
2071 if (vdi_frame_idx) {
2072 inbuf_p = t->input.paddr + t->set.i_off;
2073 inbuf = t->input.paddr_n + t->set.istride + t->set.i_off;
2074 inbuf_n = t->input.paddr_n + t->set.i_off;
2075 params.mem_prp_vf_mem.field_fmt =
2076 IPU_DEINTERLACE_FIELD_TOP;
2078 inbuf_p = t->input.paddr + t->set.istride +
2080 inbuf = t->input.paddr + t->set.i_off;
2081 inbuf_n = t->input.paddr_n + t->set.istride +
2086 if (t->input.deinterlace.enable) {
2087 if (params.mem_prp_vf_mem.field_fmt ==
2088 IPU_DEINTERLACE_FIELD_TOP) {
2089 if (vdi_frame_idx) {
2090 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2091 params.mem_prp_vf_mem.field_fmt =
2092 IPU_DEINTERLACE_FIELD_BOTTOM;
2094 inbuf = t->input.paddr + t->set.i_off;
2096 if (vdi_frame_idx) {
2097 inbuf = t->input.paddr + t->set.i_off;
2098 params.mem_prp_vf_mem.field_fmt =
2099 IPU_DEINTERLACE_FIELD_TOP;
2101 inbuf = t->input.paddr + t->set.istride + t->set.i_off;
2104 inbuf = t->input.paddr + t->set.i_off;
2108 ovbuf = t->overlay.paddr + t->set.ov_off;
2110 if (t->overlay_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
2111 ov_alp_buf = t->overlay.alpha.loc_alp_paddr
2112 + t->set.ov_alpha_off;
2114 if ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
2115 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2116 ret = ipu_init_channel_buffer(ipu,
2130 t->state = STATE_INIT_CHAN_BUF_FAIL;
2134 if (deinterlace_3_field(t) &&
2135 (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
2136 ret = ipu_init_channel_buffer(ipu,
2137 t->set.vdi_ic_p_chan,
2150 t->state = STATE_INIT_CHAN_BUF_FAIL;
2154 ret = ipu_init_channel_buffer(ipu,
2155 t->set.vdi_ic_n_chan,
2168 t->state = STATE_INIT_CHAN_BUF_FAIL;
2173 if (t->overlay_en) {
2174 ret = ipu_init_channel_buffer(ipu,
2176 IPU_GRAPH_IN_BUFFER,
2188 t->state = STATE_INIT_CHAN_BUF_FAIL;
2193 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2194 ret = ipu_init_channel_buffer(ipu,
2196 IPU_ALPHA_IN_BUFFER,
2197 IPU_PIX_FMT_GENERIC,
2200 t->set.ov_alpha_stride,
2207 t->state = STATE_INIT_CHAN_BUF_FAIL;
2212 if (!(t->set.task & VDOA_ONLY)) {
2213 ret = ipu_init_channel_buffer(ipu,
2227 t->state = STATE_INIT_CHAN_BUF_FAIL;
2232 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2233 ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2234 CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
2235 STATE_LINK_CHAN_FAIL, done, ret);
2242 static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
2246 if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
2247 ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
2248 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
2249 STATE_UNLINK_CHAN_FAIL, ret);
2251 ipu_uninit_channel(ipu, t->set.ic_chan);
2252 if (deinterlace_3_field(t)) {
2253 ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
2254 ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
2258 static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2261 dma_addr_t inbuf = 0, outbuf = 0;
2262 int in_uoff = 0, in_voff = 0;
2263 int in_fmt, in_width, in_height, in_stride;
2266 ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
2268 t->state = STATE_INIT_CHAN_FAIL;
2272 /* init channel buf */
2273 /* is it need link to a ic channel */
2274 if (ic_and_rot(t->set.mode)) {
2275 in_fmt = t->set.r_fmt;
2276 in_width = t->set.r_width;
2277 in_height = t->set.r_height;
2278 in_stride = t->set.r_stride;
2279 inbuf = t->set.r_paddr;
2283 in_fmt = t->input.format;
2284 in_width = t->input.crop.w;
2285 in_height = t->input.crop.h;
2286 in_stride = t->set.istride;
2287 inbuf = t->input.paddr + t->set.i_off;
2288 in_uoff = t->set.i_uoff;
2289 in_voff = t->set.i_voff;
2291 outbuf = t->output.paddr + t->set.o_off;
2293 ret = ipu_init_channel_buffer(ipu,
2307 t->state = STATE_INIT_CHAN_BUF_FAIL;
2311 ret = ipu_init_channel_buffer(ipu,
2325 t->state = STATE_INIT_CHAN_BUF_FAIL;
2333 static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
2335 ipu_uninit_channel(ipu, t->set.rot_chan);
2338 static int get_irq(struct ipu_task_entry *t)
2343 if (only_ic(t->set.mode))
2344 chan = t->set.ic_chan;
2346 chan = t->set.rot_chan;
2349 case MEM_ROT_VF_MEM:
2350 irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
2352 case MEM_ROT_PP_MEM:
2353 irq = IPU_IRQ_PP_ROT_OUT_EOF;
2355 case MEM_VDI_PRP_VF_MEM:
2356 case MEM_PRP_VF_MEM:
2357 irq = IPU_IRQ_PRP_VF_OUT_EOF;
2360 irq = IPU_IRQ_PP_OUT_EOF;
2363 irq = IPU_IRQ_VDIC_OUT_EOF;
2372 static irqreturn_t task_irq_handler(int irq, void *dev_id)
2374 struct ipu_task_entry *prev_tsk = dev_id;
2376 CHECK_PERF(&prev_tsk->ts_inirq);
2377 complete(&prev_tsk->irq_comp);
2378 dev_dbg(prev_tsk->dev, "[0x%p] no-0x%x in-irq!",
2379 prev_tsk, prev_tsk->task_no);
2384 /* Fix deinterlace up&down split mode medium line */
2385 static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
2393 unsigned char *base_off;
2394 struct ipu_task_entry *parent = t->parent;
2395 struct mutex *lock = &parent->vdic_lock;
2398 dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
2402 stripe_mode = t->task_no & 0xf;
2403 task_no = t->task_no >> 4;
2405 /* Save both luma and chroma part for interleaved YUV(e.g. YUYV).
2406 * Save luma part for non-interleaved and partial-interleaved
2407 * YUV format (e.g NV12 and YV12). */
2408 if (t->output.format == IPU_PIX_FMT_YUYV ||
2409 t->output.format == IPU_PIX_FMT_UYVY)
2410 line_size = t->output.crop.w * fmt_to_bpp(t->output.format)/8;
2412 line_size = t->output.crop.w;
2414 vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
2415 vdi_size = vdi_save_lines * line_size;
2416 if (vdi_save_lines <= 0) {
2417 dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
2422 /*check vditmpbuf buffer have alloced or buffer size is changed */
2423 if ((vdi_save_lines != parent->old_save_lines) ||
2424 (vdi_size != parent->old_size)) {
2425 if (parent->vditmpbuf[0] != NULL)
2426 kfree(parent->vditmpbuf[0]);
2427 if (parent->vditmpbuf[1] != NULL)
2428 kfree(parent->vditmpbuf[1]);
2430 parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
2431 if (parent->vditmpbuf[0] == NULL) {
2433 "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
2437 memset(parent->vditmpbuf[0], 0, vdi_size);
2439 parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
2440 if (parent->vditmpbuf[1] == NULL) {
2442 "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
2446 memset(parent->vditmpbuf[1], 0, vdi_size);
2448 parent->old_save_lines = vdi_save_lines;
2449 parent->old_size = vdi_size;
2452 if (pfn_valid(t->output.paddr >> PAGE_SHIFT)) {
2453 base_off = page_address(pfn_to_page(t->output.paddr >> PAGE_SHIFT));
2454 base_off += t->output.paddr & ((1 << PAGE_SHIFT) - 1);
2456 base_off = (char *)ioremap_nocache(t->output.paddr,
2457 t->output.width * t->output.height *
2458 fmt_to_bpp(t->output.format)/8);
2460 if (base_off == NULL) {
2461 dev_err(t->dev, "ERR[0x%p]Failed get virtual address\n", t);
2466 /* UP stripe or UP&LEFT stripe */
2467 if ((stripe_mode == UP_STRIPE) ||
2468 (stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
2469 if (!parent->buf0filled) {
2470 offset_addr = t->set.o_off +
2471 t->set.sp_setting.ud_split_line*t->set.ostride;
2472 dmac_flush_range(base_off + offset_addr,
2473 base_off + offset_addr + vdi_size);
2474 outer_flush_range(t->output.paddr + offset_addr,
2475 t->output.paddr + offset_addr + vdi_size);
2477 for (i = 0; i < vdi_save_lines; i++)
2478 memcpy(parent->vditmpbuf[0] + i*line_size,
2479 base_off + offset_addr +
2480 i*t->set.ostride, line_size);
2481 parent->buf0filled = true;
2483 offset_addr = t->set.o_off + (t->output.crop.h -
2484 vdi_save_lines) * t->set.ostride;
2485 for (i = 0; i < vdi_save_lines; i++)
2486 memcpy(base_off + offset_addr + i*t->set.ostride,
2487 parent->vditmpbuf[0] + i*line_size, line_size);
2489 dmac_flush_range(base_off + offset_addr,
2490 base_off + offset_addr + i*t->set.ostride);
2491 outer_flush_range(t->output.paddr + offset_addr,
2492 t->output.paddr + offset_addr + i*t->set.ostride);
2493 parent->buf0filled = false;
2496 /*Down stripe or Down&Left stripe*/
2497 else if ((stripe_mode == DOWN_STRIPE) ||
2498 (stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
2499 if (!parent->buf0filled) {
2500 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2501 dmac_flush_range(base_off + offset_addr,
2502 base_off + offset_addr + vdi_size);
2503 outer_flush_range(t->output.paddr + offset_addr,
2504 t->output.paddr + offset_addr + vdi_size);
2506 for (i = 0; i < vdi_save_lines; i++)
2507 memcpy(parent->vditmpbuf[0] + i*line_size,
2508 base_off + offset_addr + i*t->set.ostride,
2510 parent->buf0filled = true;
2512 offset_addr = t->set.o_off;
2513 for (i = 0; i < vdi_save_lines; i++)
2514 memcpy(base_off + offset_addr + i*t->set.ostride,
2515 parent->vditmpbuf[0] + i*line_size,
2518 dmac_flush_range(base_off + offset_addr,
2519 base_off + offset_addr + i*t->set.ostride);
2520 outer_flush_range(t->output.paddr + offset_addr,
2521 t->output.paddr + offset_addr + i*t->set.ostride);
2522 parent->buf0filled = false;
2526 else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
2527 if (!parent->buf1filled) {
2528 offset_addr = t->set.o_off +
2529 t->set.sp_setting.ud_split_line*t->set.ostride;
2530 dmac_flush_range(base_off + offset_addr,
2531 base_off + offset_addr + vdi_size);
2532 outer_flush_range(t->output.paddr + offset_addr,
2533 t->output.paddr + offset_addr + vdi_size);
2535 for (i = 0; i < vdi_save_lines; i++)
2536 memcpy(parent->vditmpbuf[1] + i*line_size,
2537 base_off + offset_addr + i*t->set.ostride,
2539 parent->buf1filled = true;
2541 offset_addr = t->set.o_off +
2542 (t->output.crop.h - vdi_save_lines)*t->set.ostride;
2543 for (i = 0; i < vdi_save_lines; i++)
2544 memcpy(base_off + offset_addr + i*t->set.ostride,
2545 parent->vditmpbuf[1] + i*line_size,
2548 dmac_flush_range(base_off + offset_addr,
2549 base_off + offset_addr + i*t->set.ostride);
2550 outer_flush_range(t->output.paddr + offset_addr,
2551 t->output.paddr + offset_addr + i*t->set.ostride);
2552 parent->buf1filled = false;
2555 /*Down stripe or Down&Right stript*/
2556 else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
2557 if (!parent->buf1filled) {
2558 offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2559 dmac_flush_range(base_off + offset_addr,
2560 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2561 outer_flush_range(t->output.paddr + offset_addr,
2562 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2564 for (i = 0; i < vdi_save_lines; i++)
2565 memcpy(parent->vditmpbuf[1] + i*line_size,
2566 base_off + offset_addr + i*t->set.ostride,
2568 parent->buf1filled = true;
2570 offset_addr = t->set.o_off;
2571 for (i = 0; i < vdi_save_lines; i++)
2572 memcpy(base_off + offset_addr + i*t->set.ostride,
2573 parent->vditmpbuf[1] + i*line_size,
2576 dmac_flush_range(base_off + offset_addr,
2577 base_off + offset_addr + vdi_save_lines*t->set.ostride);
2578 outer_flush_range(t->output.paddr + offset_addr,
2579 t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2580 parent->buf1filled = false;
2583 if (!pfn_valid(t->output.paddr >> PAGE_SHIFT))
2588 static void do_task_release(struct ipu_task_entry *t, int fail)
2591 struct ipu_soc *ipu = t->ipu;
2593 if (t->input.deinterlace.enable && !fail &&
2594 (t->task_no & (UP_STRIPE | DOWN_STRIPE)))
2595 vdi_split_process(ipu, t);
2597 ipu_free_irq(ipu, t->irq, t);
2599 if (t->vdoa_dma.vaddr)
2600 dma_free_coherent(t->dev,
2605 if (only_ic(t->set.mode)) {
2606 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2607 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
2608 STATE_DISABLE_CHAN_FAIL, ret);
2609 if (deinterlace_3_field(t)) {
2610 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2612 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_p",
2613 STATE_DISABLE_CHAN_FAIL, ret);
2614 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2616 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_n",
2617 STATE_DISABLE_CHAN_FAIL, ret);
2619 } else if (only_rot(t->set.mode)) {
2620 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2621 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_rot",
2622 STATE_DISABLE_CHAN_FAIL, ret);
2623 } else if (ic_and_rot(t->set.mode)) {
2624 ret = ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan);
2625 CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch",
2626 STATE_UNLINK_CHAN_FAIL, ret);
2627 ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
2628 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-rot",
2629 STATE_DISABLE_CHAN_FAIL, ret);
2630 ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
2631 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-ic",
2632 STATE_DISABLE_CHAN_FAIL, ret);
2633 if (deinterlace_3_field(t)) {
2634 ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
2636 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-p",
2637 STATE_DISABLE_CHAN_FAIL, ret);
2638 ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
2640 CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-n",
2641 STATE_DISABLE_CHAN_FAIL, ret);
2645 if (only_ic(t->set.mode))
2647 else if (only_rot(t->set.mode))
2649 else if (ic_and_rot(t->set.mode)) {
2654 t->state = STATE_OK;
2655 CHECK_PERF(&t->ts_rel);
2659 static void do_task_vdoa_only(struct ipu_task_entry *t)
2663 ret = init_tiled_ch_bufs(NULL, t);
2664 CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
2665 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2666 vdoa_stop(t->vdoa_handle);
2667 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
2668 STATE_VDOA_IRQ_TIMEOUT, out, ret);
2670 t->state = STATE_OK;
2675 static void do_task(struct ipu_task_entry *t)
2681 struct ipu_soc *ipu = t->ipu;
2683 CHECK_PERF(&t->ts_dotask);
2686 t->state = STATE_NO_IPU;
2690 init_completion(&t->irq_comp);
2691 dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
2692 t->task_no, t->task_id);
2695 if (t->set.task & IC_PP) {
2696 t->set.ic_chan = MEM_PP_MEM;
2697 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
2698 } else if (t->set.task & IC_VF) {
2699 t->set.ic_chan = MEM_PRP_VF_MEM;
2700 dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
2701 } else if (t->set.task & VDI_VF) {
2702 if (t->set.mode & VDOA_BAND_MODE) {
2703 t->set.ic_chan = MEM_VDI_MEM;
2704 if (deinterlace_3_field(t)) {
2705 t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
2706 t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
2708 dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
2711 t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
2712 if (deinterlace_3_field(t)) {
2713 t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
2714 t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
2717 "[0x%p]ic ch MEM_VDI_PRP_VF_MEM\n", t);
2721 if (t->set.task & ROT_PP) {
2722 t->set.rot_chan = MEM_ROT_PP_MEM;
2723 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
2724 } else if (t->set.task & ROT_VF) {
2725 t->set.rot_chan = MEM_ROT_VF_MEM;
2726 dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
2729 if (t->task_id == IPU_TASK_ID_VF)
2730 busy = ic_vf_pp_is_busy(ipu, true);
2731 else if (t->task_id == IPU_TASK_ID_PP)
2732 busy = ic_vf_pp_is_busy(ipu, false);
2734 dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n",
2735 t->task_no, t->task_id);
2739 dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n",
2740 (void *)t, t->task_no, t->task_id);
2741 t->state = STATE_IPU_BUSY;
2747 t->state = STATE_NO_IRQ;
2753 if (only_ic(t->set.mode)) {
2754 dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
2755 ret = init_ic(ipu, t);
2756 CHECK_RETCODE(ret < 0, "init_ic only_ic",
2757 t->state, chan_setup, ret);
2758 } else if (only_rot(t->set.mode)) {
2759 dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
2760 ret = init_rot(ipu, t);
2761 CHECK_RETCODE(ret < 0, "init_rot only_rot",
2762 t->state, chan_setup, ret);
2763 } else if (ic_and_rot(t->set.mode)) {
2764 int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1;
2766 dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
2767 t->set.r_fmt = t->output.format;
2768 if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
2769 t->set.r_width = t->output.crop.h;
2770 t->set.r_height = t->output.crop.w;
2772 t->set.r_width = t->output.crop.w;
2773 t->set.r_height = t->output.crop.h;
2775 t->set.r_stride = t->set.r_width *
2776 bytes_per_pixel(t->set.r_fmt);
2777 r_size = PAGE_ALIGN(t->set.r_width * t->set.r_height
2778 * fmt_to_bpp(t->set.r_fmt)/8);
2780 if (r_size > ipu->rot_dma[rot_idx].size) {
2781 dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t);
2783 if (ipu->rot_dma[rot_idx].vaddr)
2784 dma_free_coherent(t->dev,
2785 ipu->rot_dma[rot_idx].size,
2786 ipu->rot_dma[rot_idx].vaddr,
2787 ipu->rot_dma[rot_idx].paddr);
2789 ipu->rot_dma[rot_idx].size = r_size;
2790 ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev,
2792 &ipu->rot_dma[rot_idx].paddr,
2793 GFP_DMA | GFP_KERNEL);
2794 CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
2795 "ic_and_rot", STATE_SYS_NO_MEM,
2796 chan_setup, -ENOMEM);
2798 t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
2800 dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
2801 dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
2802 dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
2803 dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
2804 dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
2805 dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
2807 ret = init_ic(ipu, t);
2808 CHECK_RETCODE(ret < 0, "init_ic ic_and_rot",
2809 t->state, chan_setup, ret);
2810 ret = init_rot(ipu, t);
2811 CHECK_RETCODE(ret < 0, "init_rot ic_and_rot",
2812 t->state, chan_setup, ret);
2813 ret = ipu_link_channels(ipu, t->set.ic_chan,
2815 CHECK_RETCODE(ret < 0, "ipu_link_ch ic_and_rot",
2816 STATE_LINK_CHAN_FAIL, chan_setup, ret);
2818 dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t);
2819 t->state = STATE_ERR;
2823 ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, t);
2824 CHECK_RETCODE(ret < 0, "ipu_req_irq",
2825 STATE_IRQ_FAIL, chan_setup, ret);
2827 /* enable/start channel */
2828 if (only_ic(t->set.mode)) {
2829 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2830 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic",
2831 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2832 if (deinterlace_3_field(t)) {
2833 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2834 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_p",
2835 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2836 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2837 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_n",
2838 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2841 ret = ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER,
2843 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic",
2844 STATE_SEL_BUF_FAIL, chan_buf, ret);
2845 if (t->overlay_en) {
2846 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2847 IPU_GRAPH_IN_BUFFER, 0);
2848 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_g",
2849 STATE_SEL_BUF_FAIL, chan_buf, ret);
2850 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2851 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2852 IPU_ALPHA_IN_BUFFER, 0);
2853 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_a",
2854 STATE_SEL_BUF_FAIL, chan_buf,
2858 if (!(t->set.mode & VDOA_BAND_MODE)) {
2859 if (deinterlace_3_field(t))
2860 ipu_select_multi_vdi_buffer(ipu, 0);
2862 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2863 IPU_INPUT_BUFFER, 0);
2864 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
2865 STATE_SEL_BUF_FAIL, chan_buf, ret);
2868 } else if (only_rot(t->set.mode)) {
2869 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2870 CHECK_RETCODE(ret < 0, "ipu_enable_ch only_rot",
2871 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2872 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2873 IPU_OUTPUT_BUFFER, 0);
2874 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_o",
2875 STATE_SEL_BUF_FAIL, chan_buf, ret);
2876 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2877 IPU_INPUT_BUFFER, 0);
2878 CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_i",
2879 STATE_SEL_BUF_FAIL, chan_buf, ret);
2880 } else if (ic_and_rot(t->set.mode)) {
2881 ret = ipu_enable_channel(ipu, t->set.rot_chan);
2882 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-rot",
2883 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2884 ret = ipu_enable_channel(ipu, t->set.ic_chan);
2885 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-ic",
2886 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2887 if (deinterlace_3_field(t)) {
2888 ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
2889 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-p",
2890 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2891 ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
2892 CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-n",
2893 STATE_ENABLE_CHAN_FAIL, chan_en, ret);
2896 ret = ipu_select_buffer(ipu, t->set.rot_chan,
2897 IPU_OUTPUT_BUFFER, 0);
2898 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-rot-o",
2899 STATE_SEL_BUF_FAIL, chan_buf, ret);
2900 if (t->overlay_en) {
2901 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2902 IPU_GRAPH_IN_BUFFER, 0);
2903 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-g",
2904 STATE_SEL_BUF_FAIL, chan_buf, ret);
2905 if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
2906 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2907 IPU_ALPHA_IN_BUFFER, 0);
2908 CHECK_RETCODE(ret < 0, "ipu_sel_buf icrot-ic-a",
2913 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2914 IPU_OUTPUT_BUFFER, 0);
2915 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-o",
2916 STATE_SEL_BUF_FAIL, chan_buf, ret);
2917 if (deinterlace_3_field(t))
2918 ipu_select_multi_vdi_buffer(ipu, 0);
2920 ret = ipu_select_buffer(ipu, t->set.ic_chan,
2921 IPU_INPUT_BUFFER, 0);
2922 CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-i",
2923 STATE_SEL_BUF_FAIL, chan_buf, ret);
2928 t->state = STATE_IN_PROGRESS;
2930 if (t->set.mode & VDOA_BAND_MODE) {
2931 ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
2932 CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
2933 STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
2936 CHECK_PERF(&t->ts_waitirq);
2937 ret = wait_for_completion_timeout(&t->irq_comp,
2938 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
2939 CHECK_PERF(&t->ts_wakeup);
2940 CHECK_RETCODE(ret == 0, "wait_for_comp_timeout",
2941 STATE_IRQ_TIMEOUT, chan_rel, ret);
2942 dev_dbg(t->dev, "[0x%p] no-0x%x ipu irq done!", t, t->task_no);
2948 if (t->set.mode & VDOA_BAND_MODE)
2949 vdoa_stop(t->vdoa_handle);
2950 do_task_release(t, t->state >= STATE_ERR);
2954 static void do_task_vdoa_vdi(struct ipu_task_entry *t)
2960 /* FIXME: crop mode not support now */
2961 stripe_width = t->input.width >> 1;
2962 t->input.crop.pos.x = 0;
2963 t->input.crop.pos.y = 0;
2964 t->input.crop.w = stripe_width;
2965 t->input.crop.h = t->input.height;
2966 t->output.crop.w = stripe_width;
2967 t->output.crop.h = t->input.height;
2969 for (i = 0; i < 2; i++) {
2970 t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
2971 t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
2973 ret = set_crop(&t->input.crop, t->input.width, t->input.height,
2979 update_offset(t->input.format,
2980 t->input.width, t->input.height,
2981 t->input.crop.pos.x,
2982 t->input.crop.pos.y,
2983 &t->set.i_off, &t->set.i_uoff,
2984 &t->set.i_voff, &t->set.istride);
2985 dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
2986 t->set.i_off, t->set.i_uoff, t->set.istride);
2988 ret = set_crop(&t->output.crop, t->input.width,
2989 t->output.height, t->output.format);
2994 update_offset(t->output.format,
2995 t->output.width, t->output.height,
2996 t->output.crop.pos.x,
2997 t->output.crop.pos.y,
2998 &t->set.o_off, &t->set.o_uoff,
2999 &t->set.o_voff, &t->set.ostride);
3001 dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
3002 t->set.o_off, t->set.o_uoff, t->set.ostride);
3009 dev_err(t->dev, "ERR %s set_crop.\n", __func__);
3014 static void get_res_do_task(struct ipu_task_entry *t)
3017 uint32_t split_child;
3020 found = get_vdoa_ipu_res(t);
3022 dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n",
3026 if (t->set.task & VDOA_ONLY)
3027 do_task_vdoa_only(t);
3028 else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
3029 (t->set.mode & VDOA_BAND_MODE) &&
3030 (t->input.crop.w > soc_max_vdi_in_width()))
3031 do_task_vdoa_vdi(t);
3034 put_vdoa_ipu_res(t, 0);
3036 if (t->state != STATE_OK) {
3037 dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
3038 t, t->task_no, state_msg[t->state].msg);
3041 split_child = need_split(t) && t->parent;
3043 lock = &t->parent->split_lock;
3047 wake_up(&t->parent->split_waitq);
3053 static void wait_split_task_complete(struct ipu_task_entry *parent,
3054 struct ipu_split_task *sp_task, uint32_t size)
3056 struct ipu_task_entry *tsk = NULL;
3059 unsigned long flags;
3060 struct mutex *lock = &parent->split_lock;
3061 int k, busy_vf, busy_pp;
3062 struct ipu_soc *ipu;
3065 for (j = 0; j < size; j++) {
3066 rc = wait_event_timeout(
3067 parent->split_waitq,
3068 sp_task_check_done(sp_task, parent, size, &idx),
3069 msecs_to_jiffies(parent->timeout - DEF_DELAY_MS));
3071 dev_err(parent->dev,
3072 "ERR:[0x%p] no-0x%x, split_task timeout,j:%d,"
3074 parent, parent->task_no, j, size);
3079 dev_err(parent->dev,
3080 "ERR:[0x%p] no-0x%x, invalid task idx:%d\n",
3081 parent, parent->task_no, idx);
3084 tsk = sp_task[idx].child_task;
3086 if (!tsk->split_done || !tsk->ipu)
3088 "ERR:no-0x%x,split not done:%d/null ipu:0x%p\n",
3089 tsk->task_no, tsk->split_done, tsk->ipu);
3090 tsk->split_done = 0;
3094 "[0x%p] no-0x%x sp_tsk[%d] done,state:%d.\n",
3095 tsk, tsk->task_no, idx, tsk->state);
3097 CHECK_PERF(&tsk->ts_rel);
3098 PRINT_TASK_STATISTICS;
3104 if (ret == -ETIMEDOUT) {
3106 for (k = 0; k < max_ipu_no; k++) {
3107 ipu = ipu_get_soc(k);
3109 dev_err(parent->dev, "no:0x%x, null ipu:%d\n",
3110 parent->task_no, k);
3112 busy_vf = ic_vf_pp_is_busy(ipu, true);
3113 busy_pp = ic_vf_pp_is_busy(ipu, false);
3114 dev_err(parent->dev,
3115 "ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
3116 k, busy_vf, busy_pp);
3119 for (k = 0; k < size; k++) {
3120 tsk = sp_task[k].child_task;
3123 dev_err(parent->dev,
3124 "ERR: sp_task[%d][0x%p] no-0x%x done:%d,"
3125 "state:%s,on_list:%d, ipu:0x%p,timeout!\n",
3126 k, tsk, tsk->task_no, tsk->split_done,
3127 state_msg[tsk->state].msg, tsk->task_in_list,
3132 for (j = 0; j < size; j++) {
3133 tsk = sp_task[j].child_task;
3136 spin_lock_irqsave(&ipu_task_list_lock, flags);
3137 if (tsk->task_in_list) {
3138 list_del(&tsk->node);
3139 tsk->task_in_list = 0;
3141 "[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
3142 tsk, tsk->task_no, tsk->task_id);
3144 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3147 if (tsk->state != STATE_OK) {
3149 "ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n",
3150 tsk, tsk->task_no, tsk->task_id,
3151 state_msg[tsk->state].msg);
3153 kref_put(&tsk->refcount, task_mem_free);
3156 kfree(parent->vditmpbuf[0]);
3157 kfree(parent->vditmpbuf[1]);
3160 parent->state = STATE_TIMEOUT;
3162 parent->state = STATE_OK;
3166 static inline int find_task(struct ipu_task_entry **t, int thread_id)
3169 unsigned long flags;
3170 struct ipu_task_entry *tsk;
3171 struct list_head *task_list = &ipu_task_list;
3174 spin_lock_irqsave(&ipu_task_list_lock, flags);
3175 found = !list_empty(task_list);
3177 tsk = list_first_entry(task_list, struct ipu_task_entry, node);
3178 if (tsk->task_in_list) {
3179 list_del(&tsk->node);
3180 tsk->task_in_list = 0;
3182 kref_get(&tsk->refcount);
3184 "thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n",
3185 thread_id, tsk, tsk->task_no, tsk->set.mode);
3188 "thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n",
3189 thread_id, tsk->task_no, tsk->set.mode);
3191 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3196 static int ipu_task_thread(void *argv)
3198 struct ipu_task_entry *tsk;
3199 struct ipu_task_entry *sp_tsk0;
3200 struct ipu_split_task sp_task[4];
3201 /* priority lower than irq_thread */
3202 const struct sched_param param = {
3203 .sched_priority = MAX_USER_RT_PRIO/2 - 1,
3208 unsigned long flags;
3210 struct cpumask cpu_mask;
3211 struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
3214 curr_thread_id = thread_id;
3215 sched_setscheduler(current, SCHED_FIFO, ¶m);
3217 if (!data->is_vdoa) {
3218 cpu = cpumask_first(cpu_online_mask);
3219 cpumask_set_cpu(cpu, &cpu_mask);
3220 ret = sched_setaffinity(data->ipu->thread[data->id]->pid,
3223 pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret);
3225 pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu);
3228 while (!kthread_should_stop()) {
3233 wait_event_interruptible(thread_waitq, find_task(&tsk, curr_thread_id));
3236 pr_err("thread:%d can not find task.\n",
3241 /* note: other threads run split child task */
3242 split_parent = need_split(tsk) && !tsk->parent;
3243 split_child = need_split(tsk) && tsk->parent;
3245 if ((tsk->set.split_mode == RL_SPLIT) ||
3246 (tsk->set.split_mode == UD_SPLIT))
3250 ret = queue_split_task(tsk, sp_task, size);
3254 struct list_head *pos;
3256 spin_lock_irqsave(&ipu_task_list_lock, flags);
3258 sp_tsk0 = list_first_entry(&tsk->split_list,
3259 struct ipu_task_entry, node);
3260 list_del(&sp_tsk0->node);
3262 list_for_each(pos, &tsk->split_list) {
3263 struct ipu_task_entry *tmp;
3265 tmp = list_entry(pos,
3266 struct ipu_task_entry, node);
3267 tmp->task_in_list = 1;
3269 "[0x%p] no-0x%x,id:%d sp_tsk "
3270 "add_to_list.\n", tmp,
3271 tmp->task_no, tmp->task_id);
3273 /* add to global list */
3274 list_splice(&tsk->split_list, &ipu_task_list);
3276 spin_unlock_irqrestore(&ipu_task_list_lock,
3278 /* let the parent thread do the first sp_task */
3279 /* FIXME: ensure the correct sequence for split
3283 "ERR: no-0x%x,can not get split_tsk0\n",
3285 wake_up_interruptible(&thread_waitq);
3286 get_res_do_task(sp_tsk0);
3287 dev_dbg(sp_tsk0->dev,
3288 "thread:%d complete tsk no:0x%x.\n",
3289 curr_thread_id, sp_tsk0->task_no);
3290 ret = atomic_read(&req_cnt);
3292 wake_up(&res_waitq);
3293 dev_dbg(sp_tsk0->dev,
3294 "sp_tsk0 sche thread:%d no:0x%x,"
3295 "req_cnt:%d\n", curr_thread_id,
3296 sp_tsk0->task_no, ret);
3297 /* For other threads to get_res */
3302 get_res_do_task(tsk);
3304 /* wait for all 4 sp_task finished here or timeout
3305 and then release all resources */
3306 if (split_parent && !split_fail)
3307 wait_split_task_complete(tsk, sp_task, size);
3310 atomic_inc(&tsk->done);
3311 wake_up(&tsk->task_waitq);
3314 dev_dbg(tsk->dev, "thread:%d complete tsk no:0x%x-[0x%p].\n",
3315 curr_thread_id, tsk->task_no, tsk);
3316 ret = atomic_read(&req_cnt);
3318 wake_up(&res_waitq);
3319 dev_dbg(tsk->dev, "sche thread:%d no:0x%x,req_cnt:%d\n",
3320 curr_thread_id, tsk->task_no, ret);
3321 /* note: give cpu to other threads to get_res */
3325 kref_put(&tsk->refcount, task_mem_free);
3328 pr_info("ERR %s exit.\n", __func__);
3332 int ipu_check_task(struct ipu_task *task)
3334 struct ipu_task_entry *tsk;
3337 tsk = create_task_entry(task);
3339 return PTR_ERR(tsk);
3341 ret = check_task(tsk);
3343 task->input = tsk->input;
3344 task->output = tsk->output;
3345 task->overlay = tsk->overlay;
3346 dump_task_info(tsk);
3348 kref_put(&tsk->refcount, task_mem_free);
3350 pr_debug("%s ret:%d.\n", __func__, ret);
3353 EXPORT_SYMBOL_GPL(ipu_check_task);
3355 int ipu_queue_task(struct ipu_task *task)
3357 struct ipu_task_entry *tsk;
3358 unsigned long flags;
3363 tsk = create_task_entry(task);
3365 return PTR_ERR(tsk);
3367 CHECK_PERF(&tsk->ts_queue);
3368 ret = prepare_task(tsk);
3372 if (need_split(tsk)) {
3373 CHECK_PERF(&tsk->ts_dotask);
3374 CHECK_PERF(&tsk->ts_waitirq);
3375 CHECK_PERF(&tsk->ts_inirq);
3376 CHECK_PERF(&tsk->ts_wakeup);
3379 /* task_no last four bits for split task type*/
3380 tmp_task_no = atomic_inc_return(&frame_no);
3381 tsk->task_no = tmp_task_no << 4;
3382 init_waitqueue_head(&tsk->task_waitq);
3384 spin_lock_irqsave(&ipu_task_list_lock, flags);
3385 list_add_tail(&tsk->node, &ipu_task_list);
3386 tsk->task_in_list = 1;
3387 dev_dbg(tsk->dev, "[0x%p,no-0x%x] list_add_tail\n", tsk, tsk->task_no);
3388 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3389 wake_up_interruptible(&thread_waitq);
3391 ret = wait_event_timeout(tsk->task_waitq, atomic_read(&tsk->done),
3392 msecs_to_jiffies(tsk->timeout));
3394 /* note: the timeout should larger than the internal timeout!*/
3396 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x, timeout:%dms!\n",
3397 tsk, tsk->task_no, tsk->timeout);
3399 if (STATE_OK != tsk->state) {
3400 dev_err(tsk->dev, "ERR: [0x%p] no-0x%x,state %d: %s\n",
3401 tsk, tsk->task_no, tsk->state,
3402 state_msg[tsk->state].msg);
3408 spin_lock_irqsave(&ipu_task_list_lock, flags);
3409 if (tsk->task_in_list) {
3410 list_del(&tsk->node);
3411 tsk->task_in_list = 0;
3412 dev_dbg(tsk->dev, "[0x%p] no:0x%x list_del\n",
3415 spin_unlock_irqrestore(&ipu_task_list_lock, flags);
3418 CHECK_PERF(&tsk->ts_rel);
3419 PRINT_TASK_STATISTICS;
3420 if (ts_frame_avg == 0)
3421 ts_frame_avg = ts_frame.tv_nsec / NSEC_PER_USEC +
3422 ts_frame.tv_sec * USEC_PER_SEC;
3424 ts_frame_avg = (ts_frame_avg + ts_frame.tv_nsec / NSEC_PER_USEC
3425 + ts_frame.tv_sec * USEC_PER_SEC)/2;
3426 if (timespec_compare(&ts_frame, &ts_frame_max) > 0)
3427 ts_frame_max = ts_frame;
3429 atomic_inc(&frame_cnt);
3431 if ((atomic_read(&frame_cnt) % 1000) == 0)
3432 pr_debug("ipu_dev: max frame time:%ldus, avg frame time:%dus,"
3433 "frame_cnt:%d\n", ts_frame_max.tv_nsec / NSEC_PER_USEC
3434 + ts_frame_max.tv_sec * USEC_PER_SEC,
3435 ts_frame_avg, atomic_read(&frame_cnt));
3439 dev_err(tsk->dev, "ERR: no-0x%x,ipu_queue_task err:%d\n",
3442 kref_put(&tsk->refcount, task_mem_free);
3446 EXPORT_SYMBOL_GPL(ipu_queue_task);
3448 static int mxc_ipu_open(struct inode *inode, struct file *file)
3450 file->private_data = (void *)atomic_inc_return(&file_index);
3454 static long mxc_ipu_ioctl(struct file *file,
3455 unsigned int cmd, unsigned long arg)
3457 int __user *argp = (void __user *)arg;
3461 case IPU_CHECK_TASK:
3463 struct ipu_task task;
3466 (&task, (struct ipu_task *) arg,
3467 sizeof(struct ipu_task)))
3469 ret = ipu_check_task(&task);
3470 if (copy_to_user((struct ipu_task *) arg,
3471 &task, sizeof(struct ipu_task)))
3475 case IPU_QUEUE_TASK:
3477 struct ipu_task task;
3480 (&task, (struct ipu_task *) arg,
3481 sizeof(struct ipu_task)))
3483 ret = ipu_queue_task(&task);
3489 struct ipu_alloc_list *mem;
3491 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
3495 if (get_user(size, argp))
3498 mem->size = PAGE_ALIGN(size);
3500 mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
3502 GFP_DMA | GFP_KERNEL);
3503 if (mem->cpu_addr == NULL) {
3507 mem->file_index = file->private_data;
3508 mutex_lock(&ipu_alloc_lock);
3509 list_add(&mem->list, &ipu_alloc_list);
3510 mutex_unlock(&ipu_alloc_lock);
3512 dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
3513 mem->size, mem->phy_addr);
3515 if (put_user(mem->phy_addr, argp))
3522 unsigned long offset;
3523 struct ipu_alloc_list *mem;
3525 if (get_user(offset, argp))
3529 mutex_lock(&ipu_alloc_lock);
3530 list_for_each_entry(mem, &ipu_alloc_list, list) {
3531 if (mem->phy_addr == offset) {
3532 list_del(&mem->list);
3533 dma_free_coherent(ipu_dev,
3542 mutex_unlock(&ipu_alloc_lock);
3544 dev_dbg(ipu_dev, "free %d bytes @ 0x%08X\n",
3545 mem->size, mem->phy_addr);
3555 static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
3559 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
3560 struct ipu_alloc_list *mem;
3562 mutex_lock(&ipu_alloc_lock);
3563 list_for_each_entry(mem, &ipu_alloc_list, list) {
3564 if (offset == mem->phy_addr) {
3570 mutex_unlock(&ipu_alloc_lock);
3574 if (vma->vm_end - vma->vm_start > len)
3577 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
3579 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
3580 vma->vm_end - vma->vm_start,
3581 vma->vm_page_prot)) {
3589 static int mxc_ipu_release(struct inode *inode, struct file *file)
3591 struct ipu_alloc_list *mem;
3592 struct ipu_alloc_list *n;
3594 mutex_lock(&ipu_alloc_lock);
3595 list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
3596 if ((mem->cpu_addr != 0) &&
3597 (file->private_data == mem->file_index)) {
3598 list_del(&mem->list);
3599 dma_free_coherent(ipu_dev,
3603 dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
3604 mem->size, mem->phy_addr);
3608 mutex_unlock(&ipu_alloc_lock);
3609 atomic_dec(&file_index);
3614 static struct file_operations mxc_ipu_fops = {
3615 .owner = THIS_MODULE,
3616 .open = mxc_ipu_open,
3617 .mmap = mxc_ipu_mmap,
3618 .release = mxc_ipu_release,
3619 .unlocked_ioctl = mxc_ipu_ioctl,
3622 int register_ipu_device(struct ipu_soc *ipu, int id)
3626 static struct ipu_thread_data thread_data[5];
3629 major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
3631 printk(KERN_ERR "Unable to register mxc_ipu as a char device\n");
3633 goto register_cdev_fail;
3636 ipu_class = class_create(THIS_MODULE, "mxc_ipu");
3637 if (IS_ERR(ipu_class)) {
3638 ret = PTR_ERR(ipu_class);
3639 goto ipu_class_fail;
3642 ipu_dev = device_create(ipu_class, NULL, MKDEV(major, 0),
3644 if (IS_ERR(ipu_dev)) {
3645 ret = PTR_ERR(ipu_dev);
3646 goto dev_create_fail;
3648 ipu_dev->dma_mask = kmalloc(sizeof(*ipu_dev->dma_mask), GFP_KERNEL);
3649 *ipu_dev->dma_mask = DMA_BIT_MASK(32);
3650 ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32);
3652 mutex_init(&ipu_ch_tbl.lock);
3655 ipu->rot_dma[0].size = 0;
3656 ipu->rot_dma[1].size = 0;
3658 thread_data[idx].ipu = ipu;
3659 thread_data[idx].id = 0;
3660 thread_data[idx].is_vdoa = 0;
3661 ipu->thread[0] = kthread_run(ipu_task_thread, &thread_data[idx++],
3663 if (IS_ERR(ipu->thread[0])) {
3664 ret = PTR_ERR(ipu->thread[0]);
3668 thread_data[idx].ipu = ipu;
3669 thread_data[idx].id = 1;
3670 thread_data[idx].is_vdoa = 0;
3671 ipu->thread[1] = kthread_run(ipu_task_thread, &thread_data[idx++],
3673 if (IS_ERR(ipu->thread[1])) {
3674 ret = PTR_ERR(ipu->thread[1]);
3682 kthread_stop(ipu->thread[0]);
3685 device_destroy(ipu_class, MKDEV(major, 0));
3688 class_destroy(ipu_class);
3692 unregister_chrdev(major, "mxc_ipu");
3697 void unregister_ipu_device(struct ipu_soc *ipu, int id)
3701 kthread_stop(ipu->thread[0]);
3702 kthread_stop(ipu->thread[1]);
3703 for (i = 0; i < 2; i++) {
3704 if (ipu->rot_dma[i].vaddr)
3705 dma_free_coherent(ipu_dev,
3706 ipu->rot_dma[i].size,
3707 ipu->rot_dma[i].vaddr,
3708 ipu->rot_dma[i].paddr);
3712 device_destroy(ipu_class, MKDEV(major, 0));
3713 class_destroy(ipu_class);
3714 unregister_chrdev(major, "mxc_ipu");