2 * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
6 * The code contained herein is licensed under the GNU General Public
7 * License. You may obtain a copy of the GNU General Public License
8 * Version 2 or later at the following locations:
10 * http://www.opensource.org/licenses/gpl-license.html
11 * http://www.gnu.org/copyleft/gpl.html
17 * @brief IPU Use case for PRP-ENC
22 #include <linux/module.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/platform_device.h>
25 #include <linux/ipu.h>
26 #include <linux/mipi_csi2.h>
27 #include "mxc_v4l2_capture.h"
28 #include "ipu_prp_sw.h"
31 #define CAMERA_TRACE(x) (printk)x
33 #define CAMERA_TRACE(x)
36 static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE;
39 * Function definitions
43 * IPU ENC callback function.
45 * @param irq int irq line
46 * @param dev_id void * device id
48 * @return status IRQ_HANDLED for handled
50 static irqreturn_t prp_enc_callback(int irq, void *dev_id)
52 cam_data *cam = (cam_data *) dev_id;
54 if (cam->enc_callback == NULL)
57 cam->enc_callback(irq, dev_id);
63 * PrpENC enable channel setup function
65 * @param cam struct cam_data * mxc capture instance
69 static int prp_enc_setup(cam_data *cam)
71 ipu_channel_params_t enc;
73 dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
74 #ifdef CONFIG_MXC_MIPI_CSI2
80 CAMERA_TRACE("In prp_enc_setup\n");
82 printk(KERN_ERR "cam private is NULL\n");
85 memset(&enc, 0, sizeof(ipu_channel_params_t));
87 ipu_csi_get_window_size(cam->ipu, &enc.csi_prp_enc_mem.in_width,
88 &enc.csi_prp_enc_mem.in_height, cam->csi);
90 enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
91 enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width;
92 enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.height;
93 enc.csi_prp_enc_mem.csi = cam->csi;
94 if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
95 enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height;
96 enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width;
99 if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
100 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P;
102 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) {
103 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YVU420P;
105 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
106 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P;
107 pr_info("YUV422P\n");
108 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
109 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV;
111 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) {
112 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY;
114 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {
115 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12;
117 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) {
118 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24;
120 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
121 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24;
123 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
124 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565;
126 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
127 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32;
129 } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) {
130 enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32;
133 printk(KERN_ERR "format not supported\n");
137 #ifdef CONFIG_MXC_MIPI_CSI2
138 mipi_csi2_info = mipi_csi2_get_info();
140 if (mipi_csi2_info) {
141 if (mipi_csi2_get_status(mipi_csi2_info)) {
142 ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
143 csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
145 if (cam->ipu == ipu_get_soc(ipu_id)
146 && cam->csi == csi_id) {
147 enc.csi_prp_enc_mem.mipi_en = true;
148 enc.csi_prp_enc_mem.mipi_vc =
149 mipi_csi2_get_virtual_channel(mipi_csi2_info);
150 enc.csi_prp_enc_mem.mipi_id =
151 mipi_csi2_get_datatype(mipi_csi2_info);
153 mipi_csi2_pixelclk_enable(mipi_csi2_info);
155 enc.csi_prp_enc_mem.mipi_en = false;
156 enc.csi_prp_enc_mem.mipi_vc = 0;
157 enc.csi_prp_enc_mem.mipi_id = 0;
160 enc.csi_prp_enc_mem.mipi_en = false;
161 enc.csi_prp_enc_mem.mipi_vc = 0;
162 enc.csi_prp_enc_mem.mipi_id = 0;
165 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
171 err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc);
173 printk(KERN_ERR "ipu_init_channel %d\n", err);
177 grotation = cam->rotation;
178 if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
179 if (cam->rot_enc_bufs_vaddr[0]) {
180 dma_free_coherent(0, cam->rot_enc_buf_size[0],
181 cam->rot_enc_bufs_vaddr[0],
182 cam->rot_enc_bufs[0]);
184 if (cam->rot_enc_bufs_vaddr[1]) {
185 dma_free_coherent(0, cam->rot_enc_buf_size[1],
186 cam->rot_enc_bufs_vaddr[1],
187 cam->rot_enc_bufs[1]);
189 cam->rot_enc_buf_size[0] =
190 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
191 cam->rot_enc_bufs_vaddr[0] =
192 (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[0],
193 &cam->rot_enc_bufs[0],
194 GFP_DMA | GFP_KERNEL);
195 if (!cam->rot_enc_bufs_vaddr[0]) {
196 printk(KERN_ERR "alloc enc_bufs0\n");
199 cam->rot_enc_buf_size[1] =
200 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
201 cam->rot_enc_bufs_vaddr[1] =
202 (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[1],
203 &cam->rot_enc_bufs[1],
204 GFP_DMA | GFP_KERNEL);
205 if (!cam->rot_enc_bufs_vaddr[1]) {
206 dma_free_coherent(0, cam->rot_enc_buf_size[0],
207 cam->rot_enc_bufs_vaddr[0],
208 cam->rot_enc_bufs[0]);
209 cam->rot_enc_bufs_vaddr[0] = NULL;
210 cam->rot_enc_bufs[0] = 0;
211 printk(KERN_ERR "alloc enc_bufs1\n");
215 err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
217 enc.csi_prp_enc_mem.out_pixel_fmt,
218 enc.csi_prp_enc_mem.out_width,
219 enc.csi_prp_enc_mem.out_height,
220 enc.csi_prp_enc_mem.out_width,
222 cam->rot_enc_bufs[0],
223 cam->rot_enc_bufs[1], 0, 0, 0);
225 printk(KERN_ERR "CSI_PRP_ENC_MEM err\n");
229 err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL);
231 printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n");
235 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
237 enc.csi_prp_enc_mem.out_pixel_fmt,
238 enc.csi_prp_enc_mem.out_width,
239 enc.csi_prp_enc_mem.out_height,
240 enc.csi_prp_enc_mem.out_width,
242 cam->rot_enc_bufs[0],
243 cam->rot_enc_bufs[1], 0, 0, 0);
245 printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n");
250 ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
252 enc.csi_prp_enc_mem.out_pixel_fmt,
253 enc.csi_prp_enc_mem.out_height,
254 enc.csi_prp_enc_mem.out_width,
255 cam->v2f.fmt.pix.bytesperline /
256 bytes_per_pixel(enc.csi_prp_enc_mem.
260 cam->offset.u_offset,
261 cam->offset.v_offset);
263 printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n");
267 err = ipu_link_channels(cam->ipu,
268 CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
271 "link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n");
275 err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
277 printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
280 err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM);
282 printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n");
286 ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
287 IPU_OUTPUT_BUFFER, 0);
288 ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
289 IPU_OUTPUT_BUFFER, 1);
292 ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
294 enc.csi_prp_enc_mem.out_pixel_fmt,
295 enc.csi_prp_enc_mem.out_width,
296 enc.csi_prp_enc_mem.out_height,
297 cam->v2f.fmt.pix.bytesperline /
298 bytes_per_pixel(enc.csi_prp_enc_mem.
302 cam->offset.u_offset,
303 cam->offset.v_offset);
305 printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n");
308 err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
310 printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
319 * function to update physical buffer address for encorder IDMA channel
321 * @param eba physical buffer address for encorder IDMA channel
322 * @param buffer_num int buffer 0 or buffer 1
326 static int prp_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba,
331 pr_debug("eba %x\n", eba);
332 if (grotation >= IPU_ROTATE_90_RIGHT) {
333 err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
334 IPU_OUTPUT_BUFFER, *buffer_num,
337 err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
338 IPU_OUTPUT_BUFFER, *buffer_num,
342 if (grotation >= IPU_ROTATE_90_RIGHT) {
343 ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM,
346 err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
351 ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM,
354 err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
361 pr_err("ERROR: v4l2 capture: fail to update "
362 "buf%d\n", *buffer_num);
367 if (grotation >= IPU_ROTATE_90_RIGHT) {
368 ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER,
371 ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER,
375 *buffer_num = (*buffer_num == 0) ? 1 : 0;
380 * Enable encoder task
381 * @param private struct cam_data * mxc capture instance
385 static int prp_enc_enabling_tasks(void *private)
387 cam_data *cam = (cam_data *) private;
389 CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n");
391 cam->dummy_frame.vaddress = dma_alloc_coherent(0,
392 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
393 &cam->dummy_frame.paddress,
394 GFP_DMA | GFP_KERNEL);
395 if (cam->dummy_frame.vaddress == 0) {
396 pr_err("ERROR: v4l2 capture: Allocate dummy frame "
400 cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
401 cam->dummy_frame.buffer.length =
402 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
403 cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
405 if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
406 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF,
407 prp_enc_callback, 0, "Mxc Camera", cam);
409 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF,
410 prp_enc_callback, 0, "Mxc Camera", cam);
413 printk(KERN_ERR "Error registering rot irq\n");
417 err = prp_enc_setup(cam);
419 printk(KERN_ERR "prp_enc_setup %d\n", err);
427 * Disable encoder task
428 * @param private struct cam_data * mxc capture instance
432 static int prp_enc_disabling_tasks(void *private)
434 cam_data *cam = (cam_data *) private;
436 #ifdef CONFIG_MXC_MIPI_CSI2
437 void *mipi_csi2_info;
442 if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
443 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam);
444 ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
447 err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true);
448 if (cam->rotation >= IPU_ROTATE_90_RIGHT)
449 err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true);
451 ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM);
452 if (cam->rotation >= IPU_ROTATE_90_RIGHT)
453 ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM);
455 if (cam->dummy_frame.vaddress != 0) {
456 dma_free_coherent(0, cam->dummy_frame.buffer.length,
457 cam->dummy_frame.vaddress,
458 cam->dummy_frame.paddress);
459 cam->dummy_frame.vaddress = 0;
462 #ifdef CONFIG_MXC_MIPI_CSI2
463 mipi_csi2_info = mipi_csi2_get_info();
465 if (mipi_csi2_info) {
466 if (mipi_csi2_get_status(mipi_csi2_info)) {
467 ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
468 csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
470 if (cam->ipu == ipu_get_soc(ipu_id)
471 && cam->csi == csi_id)
472 mipi_csi2_pixelclk_disable(mipi_csi2_info);
475 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
486 * @param private struct cam_data * mxc capture instance
490 static int prp_enc_enable_csi(void *private)
492 cam_data *cam = (cam_data *) private;
494 return ipu_enable_csi(cam->ipu, cam->csi);
499 * @param private struct cam_data * mxc capture instance
503 static int prp_enc_disable_csi(void *private)
505 cam_data *cam = (cam_data *) private;
507 /* free csi eof irq firstly.
508 * when disable csi, wait for idmac eof.
509 * it requests eof irq again */
510 if (cam->rotation < IPU_ROTATE_90_RIGHT)
511 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam);
513 return ipu_disable_csi(cam->ipu, cam->csi);
517 * function to select PRP-ENC as the working path
519 * @param private struct cam_data * mxc capture instance
523 int prp_enc_select(void *private)
525 cam_data *cam = (cam_data *) private;
529 cam->enc_update_eba = prp_enc_eba_update;
530 cam->enc_enable = prp_enc_enabling_tasks;
531 cam->enc_disable = prp_enc_disabling_tasks;
532 cam->enc_enable_csi = prp_enc_enable_csi;
533 cam->enc_disable_csi = prp_enc_disable_csi;
540 EXPORT_SYMBOL(prp_enc_select);
543 * function to de-select PRP-ENC as the working path
545 * @param private struct cam_data * mxc capture instance
549 int prp_enc_deselect(void *private)
551 cam_data *cam = (cam_data *) private;
555 cam->enc_update_eba = NULL;
556 cam->enc_enable = NULL;
557 cam->enc_disable = NULL;
558 cam->enc_enable_csi = NULL;
559 cam->enc_disable_csi = NULL;
560 if (cam->rot_enc_bufs_vaddr[0]) {
561 dma_free_coherent(0, cam->rot_enc_buf_size[0],
562 cam->rot_enc_bufs_vaddr[0],
563 cam->rot_enc_bufs[0]);
564 cam->rot_enc_bufs_vaddr[0] = NULL;
565 cam->rot_enc_bufs[0] = 0;
567 if (cam->rot_enc_bufs_vaddr[1]) {
568 dma_free_coherent(0, cam->rot_enc_buf_size[1],
569 cam->rot_enc_bufs_vaddr[1],
570 cam->rot_enc_bufs[1]);
571 cam->rot_enc_bufs_vaddr[1] = NULL;
572 cam->rot_enc_bufs[1] = 0;
578 EXPORT_SYMBOL(prp_enc_deselect);
581 * Init the Encorder channels
583 * @return Error code indicating success or failure
585 __init int prp_enc_init(void)
591 * Deinit the Encorder channels
594 void __exit prp_enc_exit(void)
598 module_init(prp_enc_init);
599 module_exit(prp_enc_exit);
601 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
602 MODULE_DESCRIPTION("IPU PRP ENC Driver");
603 MODULE_LICENSE("GPL");