]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c
2667fca81a7632a5d1a940635f15fbb15f9d7d25
[karo-tx-linux.git] / drivers / media / platform / mxc / capture / ipu_prp_vf_sdc_bg.c
1 /*
2  * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
3  */
4
5 /*
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:
9  *
10  * http://www.opensource.org/licenses/gpl-license.html
11  * http://www.gnu.org/copyleft/gpl.html
12  */
13
14 /*!
15  * @file ipu_prp_vf_sdc_bg.c
16  *
17  * @brief IPU Use case for PRP-VF back-ground
18  *
19  * @ingroup IPU
20  */
21 #include <linux/dma-mapping.h>
22 #include <linux/fb.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"
28
29 static int buffer_num;
30 static int buffer_ready;
31 static struct ipu_soc *disp_ipu;
32
33 static void get_disp_ipu(cam_data *cam)
34 {
35         if (cam->output > 2)
36                 disp_ipu = ipu_get_soc(1); /* using DISP4 */
37         else
38                 disp_ipu = ipu_get_soc(0);
39 }
40
41 /*
42  * Function definitions
43  */
44
45 /*!
46  * SDC V-Sync callback function.
47  *
48  * @param irq       int irq line
49  * @param dev_id    void * device id
50  *
51  * @return status   IRQ_HANDLED for handled
52  */
53 static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id)
54 {
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);
59                 buffer_ready--;
60         }
61
62         return IRQ_HANDLED;
63 }
64
65 /*!
66  * VF EOF callback function.
67  *
68  * @param irq       int irq line
69  * @param dev_id    void * device id
70  *
71  * @return status   IRQ_HANDLED for handled
72  */
73 static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id)
74 {
75         cam_data *cam = dev_id;
76         pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num);
77
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);
83         buffer_ready++;
84         return IRQ_HANDLED;
85 }
86
87 /*!
88  * prpvf_start - start the vf task
89  *
90  * @param private    cam_data * mxc v4l2 main structure
91  *
92  */
93 static int prpvf_start(void *private)
94 {
95         cam_data *cam = (cam_data *) private;
96         ipu_channel_params_t vf;
97         u32 format;
98         u32 offset;
99         u32 bpp, size = 3;
100         int err = 0;
101 #ifdef CONFIG_MXC_MIPI_CSI2
102         void *mipi_csi2_info;
103         int ipu_id;
104         int csi_id;
105 #endif
106
107         if (!cam) {
108                 printk(KERN_ERR "private is NULL\n");
109                 return -EIO;
110         }
111
112         if (cam->overlay_active == true) {
113                 pr_debug("already start.\n");
114                 return 0;
115         }
116
117         get_disp_ipu(cam);
118
119         format = cam->v4l2_fb.fmt.pixelformat;
120         if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
121                 bpp = 3, size = 3;
122                 pr_info("BGR24\n");
123         } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
124                 bpp = 2, size = 2;
125                 pr_info("RGB565\n");
126         } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
127                 bpp = 4, size = 4;
128                 pr_info("BGR32\n");
129         } else {
130                 printk(KERN_ERR
131                        "unsupported fix format from the framebuffer.\n");
132                 return -EINVAL;
133         }
134
135         offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
136             size * cam->win.w.left;
137
138         if (cam->v4l2_fb.base == 0)
139                 printk(KERN_ERR "invalid frame buffer address.\n");
140         else
141                 offset += (u32) cam->v4l2_fb.base;
142
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;
153         }
154         vf.csi_prp_vf_mem.out_pixel_fmt = format;
155         size = cam->win.w.width * cam->win.w.height * size;
156
157 #ifdef CONFIG_MXC_MIPI_CSI2
158         mipi_csi2_info = mipi_csi2_get_info();
159
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);
164
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);
172
173                                 mipi_csi2_pixelclk_enable(mipi_csi2_info);
174                         } else {
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;
178                         }
179                 } else {
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;
183                 }
184         } else {
185                 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
186                        __func__, __FILE__);
187                 return -EPERM;
188         }
189 #endif
190
191         err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
192         if (err != 0)
193                 goto out_4;
194
195         if (cam->vf_bufs_vaddr[0]) {
196                 dma_free_coherent(0, cam->vf_bufs_size[0],
197                                   cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
198         }
199         if (cam->vf_bufs_vaddr[1]) {
200                 dma_free_coherent(0, cam->vf_bufs_size[1],
201                                   cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
202         }
203         cam->vf_bufs_size[0] = PAGE_ALIGN(size);
204         cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
205                                                            cam->vf_bufs_size[0],
206                                                            &cam->vf_bufs[0],
207                                                            GFP_DMA |
208                                                            GFP_KERNEL);
209         if (cam->vf_bufs_vaddr[0] == NULL) {
210                 printk(KERN_ERR "Error to allocate vf buffer\n");
211                 err = -ENOMEM;
212                 goto out_3;
213         }
214         cam->vf_bufs_size[1] = PAGE_ALIGN(size);
215         cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
216                                                            cam->vf_bufs_size[1],
217                                                            &cam->vf_bufs[1],
218                                                            GFP_DMA |
219                                                            GFP_KERNEL);
220         if (cam->vf_bufs_vaddr[1] == NULL) {
221                 printk(KERN_ERR "Error to allocate vf buffer\n");
222                 err = -ENOMEM;
223                 goto out_3;
224         }
225
226         err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
227                                       IPU_OUTPUT_BUFFER,
228                                       format, vf.csi_prp_vf_mem.out_width,
229                                       vf.csi_prp_vf_mem.out_height,
230                                       vf.csi_prp_vf_mem.out_width,
231                                       IPU_ROTATE_NONE,
232                                       cam->vf_bufs[0],
233                                       cam->vf_bufs[1],
234                                       0, 0, 0);
235         if (err != 0) {
236                 printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
237                 goto out_3;
238         }
239         err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
240         if (err != 0) {
241                 printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
242                 goto out_3;
243         }
244
245         err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
246                                       IPU_INPUT_BUFFER,
247                                       format, vf.csi_prp_vf_mem.out_width,
248                                       vf.csi_prp_vf_mem.out_height,
249                                       vf.csi_prp_vf_mem.out_width,
250                                       cam->vf_rotation,
251                                       cam->vf_bufs[0],
252                                       cam->vf_bufs[1],
253                                       0, 0, 0);
254         if (err != 0) {
255                 printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
256                 goto out_2;
257         }
258
259         if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
260                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
261                                               IPU_OUTPUT_BUFFER,
262                                               format,
263                                               vf.csi_prp_vf_mem.out_height,
264                                               vf.csi_prp_vf_mem.out_width,
265                                               cam->overlay_fb->var.xres * bpp,
266                                               IPU_ROTATE_NONE,
267                                               offset, 0, 0, 0, 0);
268
269                 if (err != 0) {
270                         printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
271                         goto out_2;
272                 }
273         } else {
274                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
275                                               IPU_OUTPUT_BUFFER,
276                                               format,
277                                               vf.csi_prp_vf_mem.out_width,
278                                               vf.csi_prp_vf_mem.out_height,
279                                               cam->overlay_fb->var.xres * bpp,
280                                               IPU_ROTATE_NONE,
281                                               offset, 0, 0, 0, 0);
282                 if (err != 0) {
283                         printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
284                         goto out_2;
285                 }
286         }
287
288         ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
289         err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
290                               prpvf_vf_eof_callback,
291                               0, "Mxc Camera", cam);
292         if (err != 0) {
293                 printk(KERN_ERR
294                        "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n");
295                 goto out_2;
296         }
297
298         ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END);
299         err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END,
300                               prpvf_sdc_vsync_callback,
301                               0, "Mxc Camera", cam);
302         if (err != 0) {
303                 printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n");
304                 goto out_1;
305         }
306
307         ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
308         ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
309
310         buffer_num = 0;
311         buffer_ready = 0;
312         ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
313
314         cam->overlay_active = true;
315         return err;
316
317 out_1:
318         ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
319 out_2:
320         ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
321 out_3:
322         ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
323 out_4:
324         if (cam->vf_bufs_vaddr[0]) {
325                 dma_free_coherent(0, cam->vf_bufs_size[0],
326                                   cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
327                 cam->vf_bufs_vaddr[0] = NULL;
328                 cam->vf_bufs[0] = 0;
329         }
330         if (cam->vf_bufs_vaddr[1]) {
331                 dma_free_coherent(0, cam->vf_bufs_size[1],
332                                   cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
333                 cam->vf_bufs_vaddr[1] = NULL;
334                 cam->vf_bufs[1] = 0;
335         }
336         if (cam->rot_vf_bufs_vaddr[0]) {
337                 dma_free_coherent(0, cam->rot_vf_buf_size[0],
338                                   cam->rot_vf_bufs_vaddr[0],
339                                   cam->rot_vf_bufs[0]);
340                 cam->rot_vf_bufs_vaddr[0] = NULL;
341                 cam->rot_vf_bufs[0] = 0;
342         }
343         if (cam->rot_vf_bufs_vaddr[1]) {
344                 dma_free_coherent(0, cam->rot_vf_buf_size[1],
345                                   cam->rot_vf_bufs_vaddr[1],
346                                   cam->rot_vf_bufs[1]);
347                 cam->rot_vf_bufs_vaddr[1] = NULL;
348                 cam->rot_vf_bufs[1] = 0;
349         }
350         return err;
351 }
352
353 /*!
354  * prpvf_stop - stop the vf task
355  *
356  * @param private    cam_data * mxc v4l2 main structure
357  *
358  */
359 static int prpvf_stop(void *private)
360 {
361         cam_data *cam = (cam_data *) private;
362 #ifdef CONFIG_MXC_MIPI_CSI2
363         void *mipi_csi2_info;
364         int ipu_id;
365         int csi_id;
366 #endif
367
368         if (cam->overlay_active == false)
369                 return 0;
370
371         ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam);
372
373         ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
374         ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
375         ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
376         ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
377
378 #ifdef CONFIG_MXC_MIPI_CSI2
379         mipi_csi2_info = mipi_csi2_get_info();
380
381         if (mipi_csi2_info) {
382                 if (mipi_csi2_get_status(mipi_csi2_info)) {
383                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
384                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
385
386                         if (cam->ipu == ipu_get_soc(ipu_id)
387                                 && cam->csi == csi_id)
388                                 mipi_csi2_pixelclk_disable(mipi_csi2_info);
389                 }
390         } else {
391                 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
392                        __func__, __FILE__);
393                 return -EPERM;
394         }
395 #endif
396
397         if (cam->vf_bufs_vaddr[0]) {
398                 dma_free_coherent(0, cam->vf_bufs_size[0],
399                                   cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
400                 cam->vf_bufs_vaddr[0] = NULL;
401                 cam->vf_bufs[0] = 0;
402         }
403         if (cam->vf_bufs_vaddr[1]) {
404                 dma_free_coherent(0, cam->vf_bufs_size[1],
405                                   cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
406                 cam->vf_bufs_vaddr[1] = NULL;
407                 cam->vf_bufs[1] = 0;
408         }
409         if (cam->rot_vf_bufs_vaddr[0]) {
410                 dma_free_coherent(0, cam->rot_vf_buf_size[0],
411                                   cam->rot_vf_bufs_vaddr[0],
412                                   cam->rot_vf_bufs[0]);
413                 cam->rot_vf_bufs_vaddr[0] = NULL;
414                 cam->rot_vf_bufs[0] = 0;
415         }
416         if (cam->rot_vf_bufs_vaddr[1]) {
417                 dma_free_coherent(0, cam->rot_vf_buf_size[1],
418                                   cam->rot_vf_bufs_vaddr[1],
419                                   cam->rot_vf_bufs[1]);
420                 cam->rot_vf_bufs_vaddr[1] = NULL;
421                 cam->rot_vf_bufs[1] = 0;
422         }
423
424         buffer_num = 0;
425         buffer_ready = 0;
426         cam->overlay_active = false;
427         return 0;
428 }
429
430 /*!
431  * Enable csi
432  * @param private       struct cam_data * mxc capture instance
433  *
434  * @return  status
435  */
436 static int prp_vf_enable_csi(void *private)
437 {
438         cam_data *cam = (cam_data *) private;
439
440         return ipu_enable_csi(cam->ipu, cam->csi);
441 }
442
443 /*!
444  * Disable csi
445  * @param private       struct cam_data * mxc capture instance
446  *
447  * @return  status
448  */
449 static int prp_vf_disable_csi(void *private)
450 {
451         cam_data *cam = (cam_data *) private;
452
453         /* free csi eof irq firstly.
454          * when disable csi, wait for idmac eof.
455          * it requests eof irq again */
456         ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
457
458         return ipu_disable_csi(cam->ipu, cam->csi);
459 }
460
461 /*!
462  * function to select PRP-VF as the working path
463  *
464  * @param private    cam_data * mxc v4l2 main structure
465  *
466  * @return  status
467  */
468 int prp_vf_sdc_select_bg(void *private)
469 {
470         cam_data *cam = (cam_data *) private;
471
472         if (cam) {
473                 cam->vf_start_sdc = prpvf_start;
474                 cam->vf_stop_sdc = prpvf_stop;
475                 cam->vf_enable_csi = prp_vf_enable_csi;
476                 cam->vf_disable_csi = prp_vf_disable_csi;
477                 cam->overlay_active = false;
478         }
479
480         return 0;
481 }
482 EXPORT_SYMBOL(prp_vf_sdc_select_bg);
483
484 /*!
485  * function to de-select PRP-VF as the working path
486  *
487  * @param private    cam_data * mxc v4l2 main structure
488  *
489  * @return  status
490  */
491 int prp_vf_sdc_deselect_bg(void *private)
492 {
493         cam_data *cam = (cam_data *) private;
494
495         if (cam) {
496                 cam->vf_start_sdc = NULL;
497                 cam->vf_stop_sdc = NULL;
498                 cam->vf_enable_csi = NULL;
499                 cam->vf_disable_csi = NULL;
500         }
501         return 0;
502 }
503 EXPORT_SYMBOL(prp_vf_sdc_deselect_bg);
504
505 /*!
506  * Init viewfinder task.
507  *
508  * @return  Error code indicating success or failure
509  */
510 __init int prp_vf_sdc_init_bg(void)
511 {
512         return 0;
513 }
514
515 /*!
516  * Deinit viewfinder task.
517  *
518  * @return  Error code indicating success or failure
519  */
520 void __exit prp_vf_sdc_exit_bg(void)
521 {
522 }
523
524 module_init(prp_vf_sdc_init_bg);
525 module_exit(prp_vf_sdc_exit_bg);
526
527 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
528 MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
529 MODULE_LICENSE("GPL");