]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.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.c
1 /*
2  * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
3  */
4 /* * The code contained herein is licensed under the GNU General Public
5  * License. You may obtain a copy of the GNU General Public License
6  * Version 2 or later at the following locations:
7  *
8  * http://www.opensource.org/licenses/gpl-license.html
9  * http://www.gnu.org/copyleft/gpl.html
10  */
11
12 /*!
13  * @file ipu_prp_vf_sdc.c
14  *
15  * @brief IPU Use case for PRP-VF
16  *
17  * @ingroup IPU
18  */
19
20 #include <linux/dma-mapping.h>
21 #include <linux/console.h>
22 #include <linux/ipu.h>
23 #include <linux/module.h>
24 #include <linux/mxcfb.h>
25 #include <mach/hardware.h>
26 #include <mach/mipi_csi2.h>
27 #include "mxc_v4l2_capture.h"
28 #include "ipu_prp_sw.h"
29
30 static int buffer_num;
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 static irqreturn_t prpvf_rot_eof_callback(int irq, void *dev_id)
42 {
43         cam_data *cam = dev_id;
44         pr_debug("buffer_num %d\n",  buffer_num);
45
46         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
47                 ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
48                                   IPU_INPUT_BUFFER, buffer_num);
49                 buffer_num = (buffer_num == 0) ? 1 : 0;
50                 ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
51                                   IPU_OUTPUT_BUFFER, buffer_num);
52         } else {
53                 ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
54                                   IPU_INPUT_BUFFER, buffer_num);
55                 buffer_num = (buffer_num == 0) ? 1 : 0;
56                 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
57                                   IPU_OUTPUT_BUFFER, buffer_num);
58         }
59         return IRQ_HANDLED;
60 }
61 /*
62  * Function definitions
63  */
64
65 /*!
66  * prpvf_start - start the vf task
67  *
68  * @param private    cam_data * mxc v4l2 main structure
69  *
70  */
71 static int prpvf_start(void *private)
72 {
73         struct fb_var_screeninfo fbvar;
74         struct fb_info *fbi = NULL;
75         cam_data *cam = (cam_data *) private;
76         ipu_channel_params_t vf;
77         u32 vf_out_format = 0;
78         u32 size = 2, temp = 0;
79         int err = 0, i = 0;
80         short *tmp, color;
81 #ifdef CONFIG_MXC_MIPI_CSI2
82         void *mipi_csi2_info;
83         int ipu_id;
84         int csi_id;
85 #endif
86
87         if (!cam) {
88                 printk(KERN_ERR "private is NULL\n");
89                 return -EIO;
90         }
91
92         if (cam->overlay_active == true) {
93                 pr_debug("already started.\n");
94                 return 0;
95         }
96
97         get_disp_ipu(cam);
98
99         for (i = 0; i < num_registered_fb; i++) {
100                 char *idstr = registered_fb[i]->fix.id;
101                 if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
102                     ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
103                         fbi = registered_fb[i];
104                         break;
105                 }
106         }
107
108         if (fbi == NULL) {
109                 printk(KERN_ERR "DISP FG fb not found\n");
110                 return -EPERM;
111         }
112
113         fbvar = fbi->var;
114
115         /* Store the overlay frame buffer's original std */
116         cam->fb_origin_std = fbvar.nonstd;
117
118         if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
119                 /* Use DP to do CSC so that we can get better performance */
120                 vf_out_format = IPU_PIX_FMT_UYVY;
121                 fbvar.nonstd = vf_out_format;
122                 color = 0x80;
123         } else {
124                 vf_out_format = IPU_PIX_FMT_RGB565;
125                 fbvar.nonstd = 0;
126                 color = 0x0;
127         }
128
129         fbvar.bits_per_pixel = 16;
130         fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
131         fbvar.yres = cam->win.w.height;
132         fbvar.yres_virtual = cam->win.w.height * 2;
133         fbvar.yoffset = 0;
134         fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
135         fbvar.activate |= FB_ACTIVATE_FORCE;
136         fb_set_var(fbi, &fbvar);
137
138         ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
139                         cam->win.w.top);
140
141         /* Fill black color for framebuffer */
142         tmp = (short *) fbi->screen_base;
143         for (i = 0; i < (fbi->fix.line_length * fbi->var.yres)/2;
144                         i++, tmp++)
145                 *tmp = color;
146
147         console_lock();
148         fb_blank(fbi, FB_BLANK_UNBLANK);
149         console_unlock();
150
151         /* correct display ch buffer address */
152         ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
153                                 0, fbi->fix.smem_start +
154                                 (fbi->fix.line_length * fbvar.yres));
155         ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
156                                         1, fbi->fix.smem_start);
157
158         memset(&vf, 0, sizeof(ipu_channel_params_t));
159         ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
160                                 &vf.csi_prp_vf_mem.in_height, cam->csi);
161         vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
162         vf.csi_prp_vf_mem.out_width = cam->win.w.width;
163         vf.csi_prp_vf_mem.out_height = cam->win.w.height;
164         vf.csi_prp_vf_mem.csi = cam->csi;
165         if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
166                 vf.csi_prp_vf_mem.out_width = cam->win.w.height;
167                 vf.csi_prp_vf_mem.out_height = cam->win.w.width;
168         }
169         vf.csi_prp_vf_mem.out_pixel_fmt = vf_out_format;
170         size = cam->win.w.width * cam->win.w.height * size;
171
172 #ifdef CONFIG_MXC_MIPI_CSI2
173         mipi_csi2_info = mipi_csi2_get_info();
174
175         if (mipi_csi2_info) {
176                 if (mipi_csi2_get_status(mipi_csi2_info)) {
177                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
178                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
179
180                         if (cam->ipu == ipu_get_soc(ipu_id)
181                                 && cam->csi == csi_id) {
182                                 vf.csi_prp_vf_mem.mipi_en = true;
183                                 vf.csi_prp_vf_mem.mipi_vc =
184                                 mipi_csi2_get_virtual_channel(mipi_csi2_info);
185                                 vf.csi_prp_vf_mem.mipi_id =
186                                 mipi_csi2_get_datatype(mipi_csi2_info);
187
188                                 mipi_csi2_pixelclk_enable(mipi_csi2_info);
189                         } else {
190                                 vf.csi_prp_vf_mem.mipi_en = false;
191                                 vf.csi_prp_vf_mem.mipi_vc = 0;
192                                 vf.csi_prp_vf_mem.mipi_id = 0;
193                         }
194                 } else {
195                         vf.csi_prp_vf_mem.mipi_en = false;
196                         vf.csi_prp_vf_mem.mipi_vc = 0;
197                         vf.csi_prp_vf_mem.mipi_id = 0;
198                 }
199         }
200 #endif
201
202         err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
203         if (err != 0)
204                 goto out_5;
205
206         if (cam->vf_bufs_vaddr[0]) {
207                 dma_free_coherent(0, cam->vf_bufs_size[0],
208                                   cam->vf_bufs_vaddr[0],
209                                   (dma_addr_t) cam->vf_bufs[0]);
210         }
211         if (cam->vf_bufs_vaddr[1]) {
212                 dma_free_coherent(0, cam->vf_bufs_size[1],
213                                   cam->vf_bufs_vaddr[1],
214                                   (dma_addr_t) cam->vf_bufs[1]);
215         }
216         cam->vf_bufs_size[0] = PAGE_ALIGN(size);
217         cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
218                                                            cam->vf_bufs_size[0],
219                                                            (dma_addr_t *) &
220                                                            cam->vf_bufs[0],
221                                                            GFP_DMA |
222                                                            GFP_KERNEL);
223         if (cam->vf_bufs_vaddr[0] == NULL) {
224                 printk(KERN_ERR "Error to allocate vf buffer\n");
225                 err = -ENOMEM;
226                 goto out_4;
227         }
228         cam->vf_bufs_size[1] = PAGE_ALIGN(size);
229         cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
230                                                            cam->vf_bufs_size[1],
231                                                            (dma_addr_t *) &
232                                                            cam->vf_bufs[1],
233                                                            GFP_DMA |
234                                                            GFP_KERNEL);
235         if (cam->vf_bufs_vaddr[1] == NULL) {
236                 printk(KERN_ERR "Error to allocate vf buffer\n");
237                 err = -ENOMEM;
238                 goto out_3;
239         }
240         pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
241
242         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
243                 err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
244                                               IPU_OUTPUT_BUFFER,
245                                               vf_out_format,
246                                               vf.csi_prp_vf_mem.out_width,
247                                               vf.csi_prp_vf_mem.out_height,
248                                               vf.csi_prp_vf_mem.out_width,
249                                               IPU_ROTATE_NONE,
250                                               cam->vf_bufs[0], cam->vf_bufs[1],
251                                               0, 0, 0);
252                 if (err != 0)
253                         goto out_3;
254
255                 err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
256                 if (err != 0) {
257                         printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
258                         goto out_3;
259                 }
260
261                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
262                                               IPU_INPUT_BUFFER,
263                                               vf_out_format,
264                                               vf.csi_prp_vf_mem.out_width,
265                                               vf.csi_prp_vf_mem.out_height,
266                                               vf.csi_prp_vf_mem.out_width,
267                                               cam->vf_rotation,
268                                               cam->vf_bufs[0],
269                                               cam->vf_bufs[1],
270                                               0, 0, 0);
271                 if (err != 0) {
272                         printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
273                         goto out_2;
274                 }
275
276                 if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) {
277                         temp = vf.csi_prp_vf_mem.out_width;
278                         vf.csi_prp_vf_mem.out_width =
279                                                 vf.csi_prp_vf_mem.out_height;
280                         vf.csi_prp_vf_mem.out_height = temp;
281                 }
282
283                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
284                                               IPU_OUTPUT_BUFFER,
285                                               vf_out_format,
286                                               vf.csi_prp_vf_mem.out_height,
287                                               vf.csi_prp_vf_mem.out_width,
288                                               vf.csi_prp_vf_mem.out_height,
289                                               IPU_ROTATE_NONE,
290                                               fbi->fix.smem_start +
291                                               (fbi->fix.line_length *
292                                                fbi->var.yres),
293                                               fbi->fix.smem_start, 0, 0, 0);
294
295                 if (err != 0) {
296                         printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
297                         goto out_2;
298                 }
299
300                 ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
301                 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF,
302                                       prpvf_rot_eof_callback,
303                               0, "Mxc Camera", cam);
304                 if (err < 0) {
305                         printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n");
306                         goto out_2;
307                 }
308
309                 err = ipu_link_channels(cam->ipu,
310                                         CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
311                 if (err < 0) {
312                         printk(KERN_ERR
313                                "Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n");
314                         goto out_1;
315                 }
316
317                 ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
318                 ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
319
320                 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
321                                   IPU_OUTPUT_BUFFER, 0);
322                 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
323                                   IPU_OUTPUT_BUFFER, 1);
324                 ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
325                                   IPU_OUTPUT_BUFFER, 0);
326         } else {
327                 err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
328                                               IPU_OUTPUT_BUFFER,
329                                               vf_out_format, cam->win.w.width,
330                                               cam->win.w.height,
331                                               cam->win.w.width,
332                                               cam->vf_rotation,
333                                               fbi->fix.smem_start +
334                                               (fbi->fix.line_length *
335                                                fbi->var.yres),
336                                               fbi->fix.smem_start, 0, 0, 0);
337                 if (err != 0) {
338                         printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
339                         goto out_4;
340                 }
341                 ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
342                 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
343                                       prpvf_rot_eof_callback,
344                               0, "Mxc Camera", cam);
345                 if (err < 0) {
346                         printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n");
347                         goto out_4;
348                 }
349
350                 ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
351
352                 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
353                                   IPU_OUTPUT_BUFFER, 0);
354         }
355
356         cam->overlay_active = true;
357         return err;
358
359 out_1:
360         ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
361 out_2:
362         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP)
363                 ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
364 out_3:
365         if (cam->vf_bufs_vaddr[0]) {
366                 dma_free_coherent(0, cam->vf_bufs_size[0],
367                                   cam->vf_bufs_vaddr[0],
368                                   (dma_addr_t) cam->vf_bufs[0]);
369                 cam->vf_bufs_vaddr[0] = NULL;
370                 cam->vf_bufs[0] = 0;
371         }
372         if (cam->vf_bufs_vaddr[1]) {
373                 dma_free_coherent(0, cam->vf_bufs_size[1],
374                                   cam->vf_bufs_vaddr[1],
375                                   (dma_addr_t) cam->vf_bufs[1]);
376                 cam->vf_bufs_vaddr[1] = NULL;
377                 cam->vf_bufs[1] = 0;
378         }
379 out_4:
380         ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
381 out_5:
382         return err;
383 }
384
385 /*!
386  * prpvf_stop - stop the vf task
387  *
388  * @param private    cam_data * mxc v4l2 main structure
389  *
390  */
391 static int prpvf_stop(void *private)
392 {
393         cam_data *cam = (cam_data *) private;
394         int err = 0, i = 0;
395         struct fb_info *fbi = NULL;
396         struct fb_var_screeninfo fbvar;
397 #ifdef CONFIG_MXC_MIPI_CSI2
398         void *mipi_csi2_info;
399         int ipu_id;
400         int csi_id;
401 #endif
402
403         if (cam->overlay_active == false)
404                 return 0;
405
406         for (i = 0; i < num_registered_fb; i++) {
407                 char *idstr = registered_fb[i]->fix.id;
408                 if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
409                     ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
410                         fbi = registered_fb[i];
411                         break;
412                 }
413         }
414
415         if (fbi == NULL) {
416                 printk(KERN_ERR "DISP FG fb not found\n");
417                 return -EPERM;
418         }
419
420         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
421                 ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
422                 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam);
423         }
424         buffer_num = 0;
425
426         ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
427
428         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
429                 ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
430                 ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
431         }
432         ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
433
434         console_lock();
435         fb_blank(fbi, FB_BLANK_POWERDOWN);
436         console_unlock();
437
438         /* Set the overlay frame buffer std to what it is used to be */
439         fbvar = fbi->var;
440         fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
441         fbvar.nonstd = cam->fb_origin_std;
442         fbvar.activate |= FB_ACTIVATE_FORCE;
443         fb_set_var(fbi, &fbvar);
444
445 #ifdef CONFIG_MXC_MIPI_CSI2
446         mipi_csi2_info = mipi_csi2_get_info();
447
448         if (mipi_csi2_info) {
449                 if (mipi_csi2_get_status(mipi_csi2_info)) {
450                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
451                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
452
453                         if (cam->ipu == ipu_get_soc(ipu_id)
454                                 && cam->csi == csi_id)
455                                 mipi_csi2_pixelclk_disable(mipi_csi2_info);
456                 }
457         }
458 #endif
459
460         if (cam->vf_bufs_vaddr[0]) {
461                 dma_free_coherent(0, cam->vf_bufs_size[0],
462                                   cam->vf_bufs_vaddr[0],
463                                   (dma_addr_t) cam->vf_bufs[0]);
464                 cam->vf_bufs_vaddr[0] = NULL;
465                 cam->vf_bufs[0] = 0;
466         }
467         if (cam->vf_bufs_vaddr[1]) {
468                 dma_free_coherent(0, cam->vf_bufs_size[1],
469                                   cam->vf_bufs_vaddr[1],
470                                   (dma_addr_t) cam->vf_bufs[1]);
471                 cam->vf_bufs_vaddr[1] = NULL;
472                 cam->vf_bufs[1] = 0;
473         }
474
475         cam->overlay_active = false;
476         return err;
477 }
478
479 /*!
480  * Enable csi
481  * @param private       struct cam_data * mxc capture instance
482  *
483  * @return  status
484  */
485 static int prp_vf_enable_csi(void *private)
486 {
487         cam_data *cam = (cam_data *) private;
488
489         return ipu_enable_csi(cam->ipu, cam->csi);
490 }
491
492 /*!
493  * Disable csi
494  * @param private       struct cam_data * mxc capture instance
495  *
496  * @return  status
497  */
498 static int prp_vf_disable_csi(void *private)
499 {
500         cam_data *cam = (cam_data *) private;
501
502         /* free csi eof irq firstly.
503          * when disable csi, wait for idmac eof.
504          * it requests eof irq again */
505         if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP)
506                 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
507
508         return ipu_disable_csi(cam->ipu, cam->csi);
509 }
510
511 /*!
512  * function to select PRP-VF as the working path
513  *
514  * @param private    cam_data * mxc v4l2 main structure
515  *
516  * @return  status
517  */
518 int prp_vf_sdc_select(void *private)
519 {
520         cam_data *cam;
521         int err = 0;
522         if (private) {
523                 cam = (cam_data *) private;
524                 cam->vf_start_sdc = prpvf_start;
525                 cam->vf_stop_sdc = prpvf_stop;
526                 cam->vf_enable_csi = prp_vf_enable_csi;
527                 cam->vf_disable_csi = prp_vf_disable_csi;
528                 cam->overlay_active = false;
529         } else
530                 err = -EIO;
531
532         return err;
533 }
534 EXPORT_SYMBOL(prp_vf_sdc_select);
535
536 /*!
537  * function to de-select PRP-VF as the working path
538  *
539  * @param private    cam_data * mxc v4l2 main structure
540  *
541  * @return  int
542  */
543 int prp_vf_sdc_deselect(void *private)
544 {
545         cam_data *cam;
546
547         if (private) {
548                 cam = (cam_data *) private;
549                 cam->vf_start_sdc = NULL;
550                 cam->vf_stop_sdc = NULL;
551                 cam->vf_enable_csi = NULL;
552                 cam->vf_disable_csi = NULL;
553         }
554         return 0;
555 }
556 EXPORT_SYMBOL(prp_vf_sdc_deselect);
557
558 /*!
559  * Init viewfinder task.
560  *
561  * @return  Error code indicating success or failure
562  */
563 __init int prp_vf_sdc_init(void)
564 {
565         return 0;
566 }
567
568 /*!
569  * Deinit viewfinder task.
570  *
571  * @return  Error code indicating success or failure
572  */
573 void __exit prp_vf_sdc_exit(void)
574 {
575 }
576
577 module_init(prp_vf_sdc_init);
578 module_exit(prp_vf_sdc_exit);
579
580 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
581 MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
582 MODULE_LICENSE("GPL");