3 * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
7 * The code contained herein is licensed under the GNU General Public
8 * License. You may obtain a copy of the GNU General Public License
9 * Version 2 or later at the following locations:
11 * http://www.opensource.org/licenses/gpl-license.html
12 * http://www.gnu.org/copyleft/gpl.html
16 * @file ipu_bg_overlay_sdc_bg.c
18 * @brief IPU Use case for PRP-VF back-ground
22 #include <linux/module.h>
23 #include <linux/dma-mapping.h>
25 #include <linux/ipu.h>
26 #include <linux/mipi_csi2.h>
27 #include "mxc_v4l2_capture.h"
28 #include "ipu_prp_sw.h"
30 static int csi_buffer_num;
31 static u32 bpp, csi_mem_bufsize = 3;
32 static u32 out_format;
33 static struct ipu_soc *disp_ipu;
36 static void csi_buf_work_func(struct work_struct *work)
40 container_of(work, struct _cam_data, csi_work_struct);
43 memset(&task, 0, sizeof(task));
46 task.input.paddr = cam->vf_bufs[0];
48 task.input.paddr = cam->vf_bufs[1];
49 task.input.width = cam->crop_current.width;
50 task.input.height = cam->crop_current.height;
51 task.input.format = IPU_PIX_FMT_UYVY;
53 task.output.paddr = offset;
54 task.output.width = cam->overlay_fb->var.xres;
55 task.output.height = cam->overlay_fb->var.yres;
56 task.output.format = out_format;
57 task.output.rotate = cam->rotation;
58 task.output.crop.pos.x = cam->win.w.left;
59 task.output.crop.pos.y = cam->win.w.top;
60 if (cam->win.w.width > 1024 || cam->win.w.height > 1024) {
61 task.output.crop.w = cam->overlay_fb->var.xres;
62 task.output.crop.h = cam->overlay_fb->var.yres;
64 task.output.crop.w = cam->win.w.width;
65 task.output.crop.h = cam->win.w.height;
68 err = ipu_check_task(&task);
69 if (err != IPU_CHECK_OK) {
70 if (err > IPU_CHECK_ERR_MIN) {
71 if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
72 task.input.crop.w -= 8;
75 if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
76 task.input.crop.h -= 8;
79 if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
80 task.output.width -= 8;
81 task.output.crop.w = task.output.width;
84 if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
85 task.output.height -= 8;
86 task.output.crop.h = task.output.height;
89 printk(KERN_ERR "check ipu taks fail\n");
92 printk(KERN_ERR "check ipu taks fail\n");
95 err = ipu_queue_task(&task);
97 printk(KERN_ERR "queue ipu task error\n");
100 static void get_disp_ipu(cam_data *cam)
103 disp_ipu = ipu_get_soc(1); /* using DISP4 */
105 disp_ipu = ipu_get_soc(0);
110 * csi ENC callback function.
112 * @param irq int irq line
113 * @param dev_id void * device id
115 * @return status IRQ_HANDLED for handled
117 static irqreturn_t csi_enc_callback(int irq, void *dev_id)
119 cam_data *cam = (cam_data *) dev_id;
121 ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, csi_buffer_num);
122 schedule_work(&cam->csi_work_struct);
123 csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
127 static int csi_enc_setup(cam_data *cam)
129 ipu_channel_params_t params;
131 int err = 0, sensor_protocol = 0;
132 #ifdef CONFIG_MXC_MIPI_CSI2
133 void *mipi_csi2_info;
139 printk(KERN_ERR "cam private is NULL\n");
143 memset(¶ms, 0, sizeof(ipu_channel_params_t));
144 params.csi_mem.csi = cam->csi;
146 sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
147 switch (sensor_protocol) {
148 case IPU_CSI_CLK_MODE_GATED_CLK:
149 case IPU_CSI_CLK_MODE_NONGATED_CLK:
150 case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
151 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
152 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
153 params.csi_mem.interlaced = false;
155 case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
156 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
157 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
158 params.csi_mem.interlaced = true;
161 printk(KERN_ERR "sensor protocol unsupported\n");
165 #ifdef CONFIG_MXC_MIPI_CSI2
166 mipi_csi2_info = mipi_csi2_get_info();
168 if (mipi_csi2_info) {
169 if (mipi_csi2_get_status(mipi_csi2_info)) {
170 ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
171 csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
173 if (cam->ipu == ipu_get_soc(ipu_id)
174 && cam->csi == csi_id) {
175 params.csi_mem.mipi_en = true;
176 params.csi_mem.mipi_vc =
177 mipi_csi2_get_virtual_channel(mipi_csi2_info);
178 params.csi_mem.mipi_id =
179 mipi_csi2_get_datatype(mipi_csi2_info);
181 mipi_csi2_pixelclk_enable(mipi_csi2_info);
183 params.csi_mem.mipi_en = false;
184 params.csi_mem.mipi_vc = 0;
185 params.csi_mem.mipi_id = 0;
188 params.csi_mem.mipi_en = false;
189 params.csi_mem.mipi_vc = 0;
190 params.csi_mem.mipi_id = 0;
193 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
199 if (cam->vf_bufs_vaddr[0]) {
200 dma_free_coherent(0, cam->vf_bufs_size[0],
201 cam->vf_bufs_vaddr[0],
202 (dma_addr_t) cam->vf_bufs[0]);
204 if (cam->vf_bufs_vaddr[1]) {
205 dma_free_coherent(0, cam->vf_bufs_size[1],
206 cam->vf_bufs_vaddr[1],
207 (dma_addr_t) cam->vf_bufs[1]);
210 cam->crop_current.width * cam->crop_current.height * 2;
211 cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
212 cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
213 cam->vf_bufs_size[0],
218 if (cam->vf_bufs_vaddr[0] == NULL) {
219 printk(KERN_ERR "Error to allocate vf buffer\n");
223 cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
224 cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
225 cam->vf_bufs_size[1],
230 if (cam->vf_bufs_vaddr[1] == NULL) {
231 printk(KERN_ERR "Error to allocate vf buffer\n");
235 pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
237 err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms);
239 printk(KERN_ERR "ipu_init_channel %d\n", err);
243 pixel_fmt = IPU_PIX_FMT_UYVY;
244 err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
245 pixel_fmt, cam->crop_current.width,
246 cam->crop_current.height,
247 cam->crop_current.width, IPU_ROTATE_NONE,
248 cam->vf_bufs[0], cam->vf_bufs[1], 0,
249 cam->offset.u_offset, cam->offset.u_offset);
251 printk(KERN_ERR "CSI_MEM output buffer\n");
254 err = ipu_enable_channel(cam->ipu, CSI_MEM);
256 printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
262 ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
263 ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 1);
266 if (cam->vf_bufs_vaddr[0]) {
267 dma_free_coherent(0, cam->vf_bufs_size[0],
268 cam->vf_bufs_vaddr[0],
269 (dma_addr_t) cam->vf_bufs[0]);
270 cam->vf_bufs_vaddr[0] = NULL;
273 if (cam->vf_bufs_vaddr[1]) {
274 dma_free_coherent(0, cam->vf_bufs_size[1],
275 cam->vf_bufs_vaddr[1],
276 (dma_addr_t) cam->vf_bufs[1]);
277 cam->vf_bufs_vaddr[1] = NULL;
285 * Enable encoder task
286 * @param private struct cam_data * mxc capture instance
290 static int csi_enc_enabling_tasks(void *private)
292 cam_data *cam = (cam_data *) private;
295 ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
296 err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
297 csi_enc_callback, 0, "Mxc Camera", cam);
299 printk(KERN_ERR "Error registering CSI0_OUT_EOF irq\n");
303 INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
305 err = csi_enc_setup(cam);
307 printk(KERN_ERR "csi_enc_setup %d\n", err);
313 ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
318 * bg_overlay_start - start the overlay task
320 * @param private cam_data * mxc v4l2 main structure
323 static int bg_overlay_start(void *private)
325 cam_data *cam = (cam_data *) private;
329 printk(KERN_ERR "private is NULL\n");
333 if (cam->overlay_active == true) {
334 pr_debug("already start.\n");
340 out_format = cam->v4l2_fb.fmt.pixelformat;
341 if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
342 bpp = 3, csi_mem_bufsize = 3;
344 } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
345 bpp = 2, csi_mem_bufsize = 2;
347 } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
348 bpp = 4, csi_mem_bufsize = 4;
352 "unsupported fix format from the framebuffer.\n");
356 offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
357 csi_mem_bufsize * cam->win.w.left;
359 if (cam->v4l2_fb.base == 0)
360 printk(KERN_ERR "invalid frame buffer address.\n");
362 offset += (u32) cam->v4l2_fb.base;
364 csi_mem_bufsize = cam->win.w.width * cam->win.w.height
367 err = csi_enc_enabling_tasks(cam);
369 printk(KERN_ERR "Error csi enc enable fail\n");
373 cam->overlay_active = true;
378 * bg_overlay_stop - stop the overlay task
380 * @param private cam_data * mxc v4l2 main structure
383 static int bg_overlay_stop(void *private)
386 cam_data *cam = (cam_data *) private;
387 #ifdef CONFIG_MXC_MIPI_CSI2
388 void *mipi_csi2_info;
393 if (cam->overlay_active == false)
396 err = ipu_disable_channel(cam->ipu, CSI_MEM, true);
398 ipu_uninit_channel(cam->ipu, CSI_MEM);
402 #ifdef CONFIG_MXC_MIPI_CSI2
403 mipi_csi2_info = mipi_csi2_get_info();
405 if (mipi_csi2_info) {
406 if (mipi_csi2_get_status(mipi_csi2_info)) {
407 ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
408 csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
410 if (cam->ipu == ipu_get_soc(ipu_id)
411 && cam->csi == csi_id)
412 mipi_csi2_pixelclk_disable(mipi_csi2_info);
415 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
421 flush_work(&cam->csi_work_struct);
422 cancel_work_sync(&cam->csi_work_struct);
424 if (cam->vf_bufs_vaddr[0]) {
425 dma_free_coherent(0, cam->vf_bufs_size[0],
426 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
427 cam->vf_bufs_vaddr[0] = NULL;
430 if (cam->vf_bufs_vaddr[1]) {
431 dma_free_coherent(0, cam->vf_bufs_size[1],
432 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
433 cam->vf_bufs_vaddr[1] = NULL;
436 if (cam->rot_vf_bufs_vaddr[0]) {
437 dma_free_coherent(0, cam->rot_vf_buf_size[0],
438 cam->rot_vf_bufs_vaddr[0],
439 cam->rot_vf_bufs[0]);
440 cam->rot_vf_bufs_vaddr[0] = NULL;
441 cam->rot_vf_bufs[0] = 0;
443 if (cam->rot_vf_bufs_vaddr[1]) {
444 dma_free_coherent(0, cam->rot_vf_buf_size[1],
445 cam->rot_vf_bufs_vaddr[1],
446 cam->rot_vf_bufs[1]);
447 cam->rot_vf_bufs_vaddr[1] = NULL;
448 cam->rot_vf_bufs[1] = 0;
451 cam->overlay_active = false;
457 * @param private struct cam_data * mxc capture instance
461 static int bg_overlay_enable_csi(void *private)
463 cam_data *cam = (cam_data *) private;
465 return ipu_enable_csi(cam->ipu, cam->csi);
470 * @param private struct cam_data * mxc capture instance
474 static int bg_overlay_disable_csi(void *private)
476 cam_data *cam = (cam_data *) private;
478 /* free csi eof irq firstly.
479 * when disable csi, wait for idmac eof.
480 * it requests eof irq again */
481 ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
483 return ipu_disable_csi(cam->ipu, cam->csi);
487 * function to select bg as the working path
489 * @param private cam_data * mxc v4l2 main structure
493 int bg_overlay_sdc_select(void *private)
495 cam_data *cam = (cam_data *) private;
498 cam->vf_start_sdc = bg_overlay_start;
499 cam->vf_stop_sdc = bg_overlay_stop;
500 cam->vf_enable_csi = bg_overlay_enable_csi;
501 cam->vf_disable_csi = bg_overlay_disable_csi;
502 cam->overlay_active = false;
507 EXPORT_SYMBOL(bg_overlay_sdc_select);
510 * function to de-select bg as the working path
512 * @param private cam_data * mxc v4l2 main structure
516 int bg_overlay_sdc_deselect(void *private)
518 cam_data *cam = (cam_data *) private;
521 cam->vf_start_sdc = NULL;
522 cam->vf_stop_sdc = NULL;
523 cam->vf_enable_csi = NULL;
524 cam->vf_disable_csi = NULL;
528 EXPORT_SYMBOL(bg_overlay_sdc_deselect);
531 * Init background overlay task.
533 * @return Error code indicating success or failure
535 __init int bg_overlay_sdc_init(void)
541 * Deinit background overlay task.
543 * @return Error code indicating success or failure
545 void __exit bg_overlay_sdc_exit(void)
549 module_init(bg_overlay_sdc_init);
550 module_exit(bg_overlay_sdc_exit);
552 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
553 MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
554 MODULE_LICENSE("GPL");