2 * Copyright 2004-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
15 * @file ipu_prp_vf_sdc_bg.c
17 * @brief IPU Use case for PRP-VF back-ground
21 #include <linux/dma-mapping.h>
23 #include <linux/ipu.h>
24 #include <linux/module.h>
25 #include <mach/mipi_csi2.h>
26 #include "mxc_v4l2_capture.h"
27 #include "ipu_prp_sw.h"
29 static int buffer_num;
30 static int buffer_ready;
31 static struct ipu_soc *disp_ipu;
33 static void get_disp_ipu(cam_data *cam)
36 disp_ipu = ipu_get_soc(1); /* using DISP4 */
38 disp_ipu = ipu_get_soc(0);
42 * Function definitions
46 * SDC V-Sync callback function.
48 * @param irq int irq line
49 * @param dev_id void * device id
51 * @return status IRQ_HANDLED for handled
53 static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id)
55 cam_data *cam = dev_id;
56 if (buffer_ready > 0) {
57 ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
58 IPU_OUTPUT_BUFFER, 0);
66 * VF EOF callback function.
68 * @param irq int irq line
69 * @param dev_id void * device id
71 * @return status IRQ_HANDLED for handled
73 static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id)
75 cam_data *cam = dev_id;
76 pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num);
78 ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
79 IPU_INPUT_BUFFER, buffer_num);
80 buffer_num = (buffer_num == 0) ? 1 : 0;
81 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
82 IPU_OUTPUT_BUFFER, buffer_num);
88 * prpvf_start - start the vf task
90 * @param private cam_data * mxc v4l2 main structure
93 static int prpvf_start(void *private)
95 cam_data *cam = (cam_data *) private;
96 ipu_channel_params_t vf;
101 #ifdef CONFIG_MXC_MIPI_CSI2
102 void *mipi_csi2_info;
108 printk(KERN_ERR "private is NULL\n");
112 if (cam->overlay_active == true) {
113 pr_debug("already start.\n");
119 format = cam->v4l2_fb.fmt.pixelformat;
120 if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
123 } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
126 } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
131 "unsupported fix format from the framebuffer.\n");
135 offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
136 size * cam->win.w.left;
138 if (cam->v4l2_fb.base == 0)
139 printk(KERN_ERR "invalid frame buffer address.\n");
141 offset += (u32) cam->v4l2_fb.base;
143 memset(&vf, 0, sizeof(ipu_channel_params_t));
144 ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
145 &vf.csi_prp_vf_mem.in_height, cam->csi);
146 vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
147 vf.csi_prp_vf_mem.out_width = cam->win.w.width;
148 vf.csi_prp_vf_mem.out_height = cam->win.w.height;
149 vf.csi_prp_vf_mem.csi = cam->csi;
150 if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
151 vf.csi_prp_vf_mem.out_width = cam->win.w.height;
152 vf.csi_prp_vf_mem.out_height = cam->win.w.width;
154 vf.csi_prp_vf_mem.out_pixel_fmt = format;
155 size = cam->win.w.width * cam->win.w.height * size;
157 #ifdef CONFIG_MXC_MIPI_CSI2
158 mipi_csi2_info = mipi_csi2_get_info();
160 if (mipi_csi2_info) {
161 if (mipi_csi2_get_status(mipi_csi2_info)) {
162 ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
163 csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
165 if (cam->ipu == ipu_get_soc(ipu_id)
166 && cam->csi == csi_id) {
167 vf.csi_prp_vf_mem.mipi_en = true;
168 vf.csi_prp_vf_mem.mipi_vc =
169 mipi_csi2_get_virtual_channel(mipi_csi2_info);
170 vf.csi_prp_vf_mem.mipi_id =
171 mipi_csi2_get_datatype(mipi_csi2_info);
173 mipi_csi2_pixelclk_enable(mipi_csi2_info);
175 vf.csi_prp_vf_mem.mipi_en = false;
176 vf.csi_prp_vf_mem.mipi_vc = 0;
177 vf.csi_prp_vf_mem.mipi_id = 0;
180 vf.csi_prp_vf_mem.mipi_en = false;
181 vf.csi_prp_vf_mem.mipi_vc = 0;
182 vf.csi_prp_vf_mem.mipi_id = 0;
187 err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
191 if (cam->vf_bufs_vaddr[0]) {
192 dma_free_coherent(0, cam->vf_bufs_size[0],
193 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
195 if (cam->vf_bufs_vaddr[1]) {
196 dma_free_coherent(0, cam->vf_bufs_size[1],
197 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
199 cam->vf_bufs_size[0] = PAGE_ALIGN(size);
200 cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
201 cam->vf_bufs_size[0],
205 if (cam->vf_bufs_vaddr[0] == NULL) {
206 printk(KERN_ERR "Error to allocate vf buffer\n");
210 cam->vf_bufs_size[1] = PAGE_ALIGN(size);
211 cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
212 cam->vf_bufs_size[1],
216 if (cam->vf_bufs_vaddr[1] == NULL) {
217 printk(KERN_ERR "Error to allocate vf buffer\n");
222 err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
224 format, vf.csi_prp_vf_mem.out_width,
225 vf.csi_prp_vf_mem.out_height,
226 vf.csi_prp_vf_mem.out_width,
232 printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
235 err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
237 printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
241 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
243 format, vf.csi_prp_vf_mem.out_width,
244 vf.csi_prp_vf_mem.out_height,
245 vf.csi_prp_vf_mem.out_width,
251 printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
255 if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
256 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
259 vf.csi_prp_vf_mem.out_height,
260 vf.csi_prp_vf_mem.out_width,
261 cam->overlay_fb->var.xres * bpp,
266 printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
270 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
273 vf.csi_prp_vf_mem.out_width,
274 vf.csi_prp_vf_mem.out_height,
275 cam->overlay_fb->var.xres * bpp,
279 printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
284 ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
285 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
286 prpvf_vf_eof_callback,
287 0, "Mxc Camera", cam);
290 "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n");
294 ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END);
295 err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END,
296 prpvf_sdc_vsync_callback,
297 0, "Mxc Camera", cam);
299 printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n");
303 ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
304 ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
308 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
310 cam->overlay_active = true;
314 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
316 ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
318 ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
320 if (cam->vf_bufs_vaddr[0]) {
321 dma_free_coherent(0, cam->vf_bufs_size[0],
322 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
323 cam->vf_bufs_vaddr[0] = NULL;
326 if (cam->vf_bufs_vaddr[1]) {
327 dma_free_coherent(0, cam->vf_bufs_size[1],
328 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
329 cam->vf_bufs_vaddr[1] = NULL;
332 if (cam->rot_vf_bufs_vaddr[0]) {
333 dma_free_coherent(0, cam->rot_vf_buf_size[0],
334 cam->rot_vf_bufs_vaddr[0],
335 cam->rot_vf_bufs[0]);
336 cam->rot_vf_bufs_vaddr[0] = NULL;
337 cam->rot_vf_bufs[0] = 0;
339 if (cam->rot_vf_bufs_vaddr[1]) {
340 dma_free_coherent(0, cam->rot_vf_buf_size[1],
341 cam->rot_vf_bufs_vaddr[1],
342 cam->rot_vf_bufs[1]);
343 cam->rot_vf_bufs_vaddr[1] = NULL;
344 cam->rot_vf_bufs[1] = 0;
350 * prpvf_stop - stop the vf task
352 * @param private cam_data * mxc v4l2 main structure
355 static int prpvf_stop(void *private)
357 cam_data *cam = (cam_data *) private;
358 #ifdef CONFIG_MXC_MIPI_CSI2
359 void *mipi_csi2_info;
364 if (cam->overlay_active == false)
367 ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam);
369 ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
370 ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
371 ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
372 ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
374 #ifdef CONFIG_MXC_MIPI_CSI2
375 mipi_csi2_info = mipi_csi2_get_info();
377 if (mipi_csi2_info) {
378 if (mipi_csi2_get_status(mipi_csi2_info)) {
379 ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
380 csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
382 if (cam->ipu == ipu_get_soc(ipu_id)
383 && cam->csi == csi_id)
384 mipi_csi2_pixelclk_disable(mipi_csi2_info);
389 if (cam->vf_bufs_vaddr[0]) {
390 dma_free_coherent(0, cam->vf_bufs_size[0],
391 cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
392 cam->vf_bufs_vaddr[0] = NULL;
395 if (cam->vf_bufs_vaddr[1]) {
396 dma_free_coherent(0, cam->vf_bufs_size[1],
397 cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
398 cam->vf_bufs_vaddr[1] = NULL;
401 if (cam->rot_vf_bufs_vaddr[0]) {
402 dma_free_coherent(0, cam->rot_vf_buf_size[0],
403 cam->rot_vf_bufs_vaddr[0],
404 cam->rot_vf_bufs[0]);
405 cam->rot_vf_bufs_vaddr[0] = NULL;
406 cam->rot_vf_bufs[0] = 0;
408 if (cam->rot_vf_bufs_vaddr[1]) {
409 dma_free_coherent(0, cam->rot_vf_buf_size[1],
410 cam->rot_vf_bufs_vaddr[1],
411 cam->rot_vf_bufs[1]);
412 cam->rot_vf_bufs_vaddr[1] = NULL;
413 cam->rot_vf_bufs[1] = 0;
418 cam->overlay_active = false;
424 * @param private struct cam_data * mxc capture instance
428 static int prp_vf_enable_csi(void *private)
430 cam_data *cam = (cam_data *) private;
432 return ipu_enable_csi(cam->ipu, cam->csi);
437 * @param private struct cam_data * mxc capture instance
441 static int prp_vf_disable_csi(void *private)
443 cam_data *cam = (cam_data *) private;
445 /* free csi eof irq firstly.
446 * when disable csi, wait for idmac eof.
447 * it requests eof irq again */
448 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
450 return ipu_disable_csi(cam->ipu, cam->csi);
454 * function to select PRP-VF as the working path
456 * @param private cam_data * mxc v4l2 main structure
460 int prp_vf_sdc_select_bg(void *private)
462 cam_data *cam = (cam_data *) private;
465 cam->vf_start_sdc = prpvf_start;
466 cam->vf_stop_sdc = prpvf_stop;
467 cam->vf_enable_csi = prp_vf_enable_csi;
468 cam->vf_disable_csi = prp_vf_disable_csi;
469 cam->overlay_active = false;
474 EXPORT_SYMBOL(prp_vf_sdc_select_bg);
477 * function to de-select PRP-VF as the working path
479 * @param private cam_data * mxc v4l2 main structure
483 int prp_vf_sdc_deselect_bg(void *private)
485 cam_data *cam = (cam_data *) private;
488 cam->vf_start_sdc = NULL;
489 cam->vf_stop_sdc = NULL;
490 cam->vf_enable_csi = NULL;
491 cam->vf_disable_csi = NULL;
495 EXPORT_SYMBOL(prp_vf_sdc_deselect_bg);
498 * Init viewfinder task.
500 * @return Error code indicating success or failure
502 __init int prp_vf_sdc_init_bg(void)
508 * Deinit viewfinder task.
510 * @return Error code indicating success or failure
512 void __exit prp_vf_sdc_exit_bg(void)
516 module_init(prp_vf_sdc_init_bg);
517 module_exit(prp_vf_sdc_exit_bg);
519 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
520 MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
521 MODULE_LICENSE("GPL");