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
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;
167 err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc);
169 printk(KERN_ERR "ipu_init_channel %d\n", err);
173 grotation = cam->rotation;
174 if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
175 if (cam->rot_enc_bufs_vaddr[0]) {
176 dma_free_coherent(0, cam->rot_enc_buf_size[0],
177 cam->rot_enc_bufs_vaddr[0],
178 cam->rot_enc_bufs[0]);
180 if (cam->rot_enc_bufs_vaddr[1]) {
181 dma_free_coherent(0, cam->rot_enc_buf_size[1],
182 cam->rot_enc_bufs_vaddr[1],
183 cam->rot_enc_bufs[1]);
185 cam->rot_enc_buf_size[0] =
186 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
187 cam->rot_enc_bufs_vaddr[0] =
188 (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[0],
189 &cam->rot_enc_bufs[0],
190 GFP_DMA | GFP_KERNEL);
191 if (!cam->rot_enc_bufs_vaddr[0]) {
192 printk(KERN_ERR "alloc enc_bufs0\n");
195 cam->rot_enc_buf_size[1] =
196 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
197 cam->rot_enc_bufs_vaddr[1] =
198 (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[1],
199 &cam->rot_enc_bufs[1],
200 GFP_DMA | GFP_KERNEL);
201 if (!cam->rot_enc_bufs_vaddr[1]) {
202 dma_free_coherent(0, cam->rot_enc_buf_size[0],
203 cam->rot_enc_bufs_vaddr[0],
204 cam->rot_enc_bufs[0]);
205 cam->rot_enc_bufs_vaddr[0] = NULL;
206 cam->rot_enc_bufs[0] = 0;
207 printk(KERN_ERR "alloc enc_bufs1\n");
211 err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
213 enc.csi_prp_enc_mem.out_pixel_fmt,
214 enc.csi_prp_enc_mem.out_width,
215 enc.csi_prp_enc_mem.out_height,
216 enc.csi_prp_enc_mem.out_width,
218 cam->rot_enc_bufs[0],
219 cam->rot_enc_bufs[1], 0, 0, 0);
221 printk(KERN_ERR "CSI_PRP_ENC_MEM err\n");
225 err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL);
227 printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n");
231 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
233 enc.csi_prp_enc_mem.out_pixel_fmt,
234 enc.csi_prp_enc_mem.out_width,
235 enc.csi_prp_enc_mem.out_height,
236 enc.csi_prp_enc_mem.out_width,
238 cam->rot_enc_bufs[0],
239 cam->rot_enc_bufs[1], 0, 0, 0);
241 printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n");
246 ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
248 enc.csi_prp_enc_mem.out_pixel_fmt,
249 enc.csi_prp_enc_mem.out_height,
250 enc.csi_prp_enc_mem.out_width,
251 cam->v2f.fmt.pix.bytesperline /
252 bytes_per_pixel(enc.csi_prp_enc_mem.
256 cam->offset.u_offset,
257 cam->offset.v_offset);
259 printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n");
263 err = ipu_link_channels(cam->ipu,
264 CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
267 "link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n");
271 err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
273 printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
276 err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM);
278 printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n");
282 ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
283 IPU_OUTPUT_BUFFER, 0);
284 ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
285 IPU_OUTPUT_BUFFER, 1);
288 ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
290 enc.csi_prp_enc_mem.out_pixel_fmt,
291 enc.csi_prp_enc_mem.out_width,
292 enc.csi_prp_enc_mem.out_height,
293 cam->v2f.fmt.pix.bytesperline /
294 bytes_per_pixel(enc.csi_prp_enc_mem.
298 cam->offset.u_offset,
299 cam->offset.v_offset);
301 printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n");
304 err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
306 printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
315 * function to update physical buffer address for encorder IDMA channel
317 * @param eba physical buffer address for encorder IDMA channel
318 * @param buffer_num int buffer 0 or buffer 1
322 static int prp_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba,
327 pr_debug("eba %x\n", eba);
328 if (grotation >= IPU_ROTATE_90_RIGHT) {
329 err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
330 IPU_OUTPUT_BUFFER, *buffer_num,
333 err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
334 IPU_OUTPUT_BUFFER, *buffer_num,
338 if (grotation >= IPU_ROTATE_90_RIGHT) {
339 ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM,
342 err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
347 ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM,
350 err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
357 pr_err("ERROR: v4l2 capture: fail to update "
358 "buf%d\n", *buffer_num);
363 if (grotation >= IPU_ROTATE_90_RIGHT) {
364 ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER,
367 ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER,
371 *buffer_num = (*buffer_num == 0) ? 1 : 0;
376 * Enable encoder task
377 * @param private struct cam_data * mxc capture instance
381 static int prp_enc_enabling_tasks(void *private)
383 cam_data *cam = (cam_data *) private;
385 CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n");
387 cam->dummy_frame.vaddress = dma_alloc_coherent(0,
388 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
389 &cam->dummy_frame.paddress,
390 GFP_DMA | GFP_KERNEL);
391 if (cam->dummy_frame.vaddress == 0) {
392 pr_err("ERROR: v4l2 capture: Allocate dummy frame "
396 cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
397 cam->dummy_frame.buffer.length =
398 PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
399 cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
401 if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
402 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF,
403 prp_enc_callback, 0, "Mxc Camera", cam);
405 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF,
406 prp_enc_callback, 0, "Mxc Camera", cam);
409 printk(KERN_ERR "Error registering rot irq\n");
413 err = prp_enc_setup(cam);
415 printk(KERN_ERR "prp_enc_setup %d\n", err);
423 * Disable encoder task
424 * @param private struct cam_data * mxc capture instance
428 static int prp_enc_disabling_tasks(void *private)
430 cam_data *cam = (cam_data *) private;
432 #ifdef CONFIG_MXC_MIPI_CSI2
433 void *mipi_csi2_info;
438 if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
439 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam);
440 ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
443 err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true);
444 if (cam->rotation >= IPU_ROTATE_90_RIGHT)
445 err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true);
447 ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM);
448 if (cam->rotation >= IPU_ROTATE_90_RIGHT)
449 ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM);
451 if (cam->dummy_frame.vaddress != 0) {
452 dma_free_coherent(0, cam->dummy_frame.buffer.length,
453 cam->dummy_frame.vaddress,
454 cam->dummy_frame.paddress);
455 cam->dummy_frame.vaddress = 0;
458 #ifdef CONFIG_MXC_MIPI_CSI2
459 mipi_csi2_info = mipi_csi2_get_info();
461 if (mipi_csi2_info) {
462 if (mipi_csi2_get_status(mipi_csi2_info)) {
463 ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
464 csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
466 if (cam->ipu == ipu_get_soc(ipu_id)
467 && cam->csi == csi_id)
468 mipi_csi2_pixelclk_disable(mipi_csi2_info);
478 * @param private struct cam_data * mxc capture instance
482 static int prp_enc_enable_csi(void *private)
484 cam_data *cam = (cam_data *) private;
486 return ipu_enable_csi(cam->ipu, cam->csi);
491 * @param private struct cam_data * mxc capture instance
495 static int prp_enc_disable_csi(void *private)
497 cam_data *cam = (cam_data *) private;
499 /* free csi eof irq firstly.
500 * when disable csi, wait for idmac eof.
501 * it requests eof irq again */
502 if (cam->rotation < IPU_ROTATE_90_RIGHT)
503 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam);
505 return ipu_disable_csi(cam->ipu, cam->csi);
509 * function to select PRP-ENC as the working path
511 * @param private struct cam_data * mxc capture instance
515 int prp_enc_select(void *private)
517 cam_data *cam = (cam_data *) private;
521 cam->enc_update_eba = prp_enc_eba_update;
522 cam->enc_enable = prp_enc_enabling_tasks;
523 cam->enc_disable = prp_enc_disabling_tasks;
524 cam->enc_enable_csi = prp_enc_enable_csi;
525 cam->enc_disable_csi = prp_enc_disable_csi;
532 EXPORT_SYMBOL(prp_enc_select);
535 * function to de-select PRP-ENC as the working path
537 * @param private struct cam_data * mxc capture instance
541 int prp_enc_deselect(void *private)
543 cam_data *cam = (cam_data *) private;
547 cam->enc_update_eba = NULL;
548 cam->enc_enable = NULL;
549 cam->enc_disable = NULL;
550 cam->enc_enable_csi = NULL;
551 cam->enc_disable_csi = NULL;
552 if (cam->rot_enc_bufs_vaddr[0]) {
553 dma_free_coherent(0, cam->rot_enc_buf_size[0],
554 cam->rot_enc_bufs_vaddr[0],
555 cam->rot_enc_bufs[0]);
556 cam->rot_enc_bufs_vaddr[0] = NULL;
557 cam->rot_enc_bufs[0] = 0;
559 if (cam->rot_enc_bufs_vaddr[1]) {
560 dma_free_coherent(0, cam->rot_enc_buf_size[1],
561 cam->rot_enc_bufs_vaddr[1],
562 cam->rot_enc_bufs[1]);
563 cam->rot_enc_bufs_vaddr[1] = NULL;
564 cam->rot_enc_bufs[1] = 0;
570 EXPORT_SYMBOL(prp_enc_deselect);
573 * Init the Encorder channels
575 * @return Error code indicating success or failure
577 __init int prp_enc_init(void)
583 * Deinit the Encorder channels
586 void __exit prp_enc_exit(void)
590 module_init(prp_enc_init);
591 module_exit(prp_enc_exit);
593 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
594 MODULE_DESCRIPTION("IPU PRP ENC Driver");
595 MODULE_LICENSE("GPL");