]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c
ENGR00303663 mxc v4l2 capture: Don't return error if we cannot get mipi csi2
[karo-tx-linux.git] / drivers / media / platform / mxc / capture / ipu_prp_vf_sdc_bg.c
1 /*
2  * Copyright 2004-2014 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         }
185 #endif
186
187         err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
188         if (err != 0)
189                 goto out_4;
190
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]);
194         }
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]);
198         }
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],
202                                                            &cam->vf_bufs[0],
203                                                            GFP_DMA |
204                                                            GFP_KERNEL);
205         if (cam->vf_bufs_vaddr[0] == NULL) {
206                 printk(KERN_ERR "Error to allocate vf buffer\n");
207                 err = -ENOMEM;
208                 goto out_3;
209         }
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],
213                                                            &cam->vf_bufs[1],
214                                                            GFP_DMA |
215                                                            GFP_KERNEL);
216         if (cam->vf_bufs_vaddr[1] == NULL) {
217                 printk(KERN_ERR "Error to allocate vf buffer\n");
218                 err = -ENOMEM;
219                 goto out_3;
220         }
221
222         err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
223                                       IPU_OUTPUT_BUFFER,
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,
227                                       IPU_ROTATE_NONE,
228                                       cam->vf_bufs[0],
229                                       cam->vf_bufs[1],
230                                       0, 0, 0);
231         if (err != 0) {
232                 printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
233                 goto out_3;
234         }
235         err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
236         if (err != 0) {
237                 printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
238                 goto out_3;
239         }
240
241         err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
242                                       IPU_INPUT_BUFFER,
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,
246                                       cam->vf_rotation,
247                                       cam->vf_bufs[0],
248                                       cam->vf_bufs[1],
249                                       0, 0, 0);
250         if (err != 0) {
251                 printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
252                 goto out_2;
253         }
254
255         if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
256                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
257                                               IPU_OUTPUT_BUFFER,
258                                               format,
259                                               vf.csi_prp_vf_mem.out_height,
260                                               vf.csi_prp_vf_mem.out_width,
261                                               cam->overlay_fb->var.xres * bpp,
262                                               IPU_ROTATE_NONE,
263                                               offset, 0, 0, 0, 0);
264
265                 if (err != 0) {
266                         printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
267                         goto out_2;
268                 }
269         } else {
270                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
271                                               IPU_OUTPUT_BUFFER,
272                                               format,
273                                               vf.csi_prp_vf_mem.out_width,
274                                               vf.csi_prp_vf_mem.out_height,
275                                               cam->overlay_fb->var.xres * bpp,
276                                               IPU_ROTATE_NONE,
277                                               offset, 0, 0, 0, 0);
278                 if (err != 0) {
279                         printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
280                         goto out_2;
281                 }
282         }
283
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);
288         if (err != 0) {
289                 printk(KERN_ERR
290                        "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n");
291                 goto out_2;
292         }
293
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);
298         if (err != 0) {
299                 printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n");
300                 goto out_1;
301         }
302
303         ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
304         ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
305
306         buffer_num = 0;
307         buffer_ready = 0;
308         ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
309
310         cam->overlay_active = true;
311         return err;
312
313 out_1:
314         ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
315 out_2:
316         ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
317 out_3:
318         ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
319 out_4:
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;
324                 cam->vf_bufs[0] = 0;
325         }
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;
330                 cam->vf_bufs[1] = 0;
331         }
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;
338         }
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;
345         }
346         return err;
347 }
348
349 /*!
350  * prpvf_stop - stop the vf task
351  *
352  * @param private    cam_data * mxc v4l2 main structure
353  *
354  */
355 static int prpvf_stop(void *private)
356 {
357         cam_data *cam = (cam_data *) private;
358 #ifdef CONFIG_MXC_MIPI_CSI2
359         void *mipi_csi2_info;
360         int ipu_id;
361         int csi_id;
362 #endif
363
364         if (cam->overlay_active == false)
365                 return 0;
366
367         ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam);
368
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);
373
374 #ifdef CONFIG_MXC_MIPI_CSI2
375         mipi_csi2_info = mipi_csi2_get_info();
376
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);
381
382                         if (cam->ipu == ipu_get_soc(ipu_id)
383                                 && cam->csi == csi_id)
384                                 mipi_csi2_pixelclk_disable(mipi_csi2_info);
385                 }
386         }
387 #endif
388
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;
393                 cam->vf_bufs[0] = 0;
394         }
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;
399                 cam->vf_bufs[1] = 0;
400         }
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;
407         }
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;
414         }
415
416         buffer_num = 0;
417         buffer_ready = 0;
418         cam->overlay_active = false;
419         return 0;
420 }
421
422 /*!
423  * Enable csi
424  * @param private       struct cam_data * mxc capture instance
425  *
426  * @return  status
427  */
428 static int prp_vf_enable_csi(void *private)
429 {
430         cam_data *cam = (cam_data *) private;
431
432         return ipu_enable_csi(cam->ipu, cam->csi);
433 }
434
435 /*!
436  * Disable csi
437  * @param private       struct cam_data * mxc capture instance
438  *
439  * @return  status
440  */
441 static int prp_vf_disable_csi(void *private)
442 {
443         cam_data *cam = (cam_data *) private;
444
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);
449
450         return ipu_disable_csi(cam->ipu, cam->csi);
451 }
452
453 /*!
454  * function to select PRP-VF as the working path
455  *
456  * @param private    cam_data * mxc v4l2 main structure
457  *
458  * @return  status
459  */
460 int prp_vf_sdc_select_bg(void *private)
461 {
462         cam_data *cam = (cam_data *) private;
463
464         if (cam) {
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;
470         }
471
472         return 0;
473 }
474 EXPORT_SYMBOL(prp_vf_sdc_select_bg);
475
476 /*!
477  * function to de-select PRP-VF as the working path
478  *
479  * @param private    cam_data * mxc v4l2 main structure
480  *
481  * @return  status
482  */
483 int prp_vf_sdc_deselect_bg(void *private)
484 {
485         cam_data *cam = (cam_data *) private;
486
487         if (cam) {
488                 cam->vf_start_sdc = NULL;
489                 cam->vf_stop_sdc = NULL;
490                 cam->vf_enable_csi = NULL;
491                 cam->vf_disable_csi = NULL;
492         }
493         return 0;
494 }
495 EXPORT_SYMBOL(prp_vf_sdc_deselect_bg);
496
497 /*!
498  * Init viewfinder task.
499  *
500  * @return  Error code indicating success or failure
501  */
502 __init int prp_vf_sdc_init_bg(void)
503 {
504         return 0;
505 }
506
507 /*!
508  * Deinit viewfinder task.
509  *
510  * @return  Error code indicating success or failure
511  */
512 void __exit prp_vf_sdc_exit_bg(void)
513 {
514 }
515
516 module_init(prp_vf_sdc_init_bg);
517 module_exit(prp_vf_sdc_exit_bg);
518
519 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
520 MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
521 MODULE_LICENSE("GPL");