]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c
8bf5344df684ac4d2d4d7935a4abf5a70c8740b2
[karo-tx-linux.git] / drivers / media / platform / mxc / capture / ipu_prp_vf_sdc.c
1 /*
2  * Copyright 2004-2013 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         } else {
200                 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
201                        __func__, __FILE__);
202                 return -EPERM;
203         }
204 #endif
205
206         err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
207         if (err != 0)
208                 goto out_5;
209
210         if (cam->vf_bufs_vaddr[0]) {
211                 dma_free_coherent(0, cam->vf_bufs_size[0],
212                                   cam->vf_bufs_vaddr[0],
213                                   (dma_addr_t) cam->vf_bufs[0]);
214         }
215         if (cam->vf_bufs_vaddr[1]) {
216                 dma_free_coherent(0, cam->vf_bufs_size[1],
217                                   cam->vf_bufs_vaddr[1],
218                                   (dma_addr_t) cam->vf_bufs[1]);
219         }
220         cam->vf_bufs_size[0] = PAGE_ALIGN(size);
221         cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
222                                                            cam->vf_bufs_size[0],
223                                                            (dma_addr_t *) &
224                                                            cam->vf_bufs[0],
225                                                            GFP_DMA |
226                                                            GFP_KERNEL);
227         if (cam->vf_bufs_vaddr[0] == NULL) {
228                 printk(KERN_ERR "Error to allocate vf buffer\n");
229                 err = -ENOMEM;
230                 goto out_4;
231         }
232         cam->vf_bufs_size[1] = PAGE_ALIGN(size);
233         cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
234                                                            cam->vf_bufs_size[1],
235                                                            (dma_addr_t *) &
236                                                            cam->vf_bufs[1],
237                                                            GFP_DMA |
238                                                            GFP_KERNEL);
239         if (cam->vf_bufs_vaddr[1] == NULL) {
240                 printk(KERN_ERR "Error to allocate vf buffer\n");
241                 err = -ENOMEM;
242                 goto out_3;
243         }
244         pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
245
246         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
247                 err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
248                                               IPU_OUTPUT_BUFFER,
249                                               vf_out_format,
250                                               vf.csi_prp_vf_mem.out_width,
251                                               vf.csi_prp_vf_mem.out_height,
252                                               vf.csi_prp_vf_mem.out_width,
253                                               IPU_ROTATE_NONE,
254                                               cam->vf_bufs[0], cam->vf_bufs[1],
255                                               0, 0, 0);
256                 if (err != 0)
257                         goto out_3;
258
259                 err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
260                 if (err != 0) {
261                         printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
262                         goto out_3;
263                 }
264
265                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
266                                               IPU_INPUT_BUFFER,
267                                               vf_out_format,
268                                               vf.csi_prp_vf_mem.out_width,
269                                               vf.csi_prp_vf_mem.out_height,
270                                               vf.csi_prp_vf_mem.out_width,
271                                               cam->vf_rotation,
272                                               cam->vf_bufs[0],
273                                               cam->vf_bufs[1],
274                                               0, 0, 0);
275                 if (err != 0) {
276                         printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
277                         goto out_2;
278                 }
279
280                 if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) {
281                         temp = vf.csi_prp_vf_mem.out_width;
282                         vf.csi_prp_vf_mem.out_width =
283                                                 vf.csi_prp_vf_mem.out_height;
284                         vf.csi_prp_vf_mem.out_height = temp;
285                 }
286
287                 err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
288                                               IPU_OUTPUT_BUFFER,
289                                               vf_out_format,
290                                               vf.csi_prp_vf_mem.out_height,
291                                               vf.csi_prp_vf_mem.out_width,
292                                               vf.csi_prp_vf_mem.out_height,
293                                               IPU_ROTATE_NONE,
294                                               fbi->fix.smem_start +
295                                               (fbi->fix.line_length *
296                                                fbi->var.yres),
297                                               fbi->fix.smem_start, 0, 0, 0);
298
299                 if (err != 0) {
300                         printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
301                         goto out_2;
302                 }
303
304                 ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
305                 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF,
306                                       prpvf_rot_eof_callback,
307                               0, "Mxc Camera", cam);
308                 if (err < 0) {
309                         printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n");
310                         goto out_2;
311                 }
312
313                 err = ipu_link_channels(cam->ipu,
314                                         CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
315                 if (err < 0) {
316                         printk(KERN_ERR
317                                "Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n");
318                         goto out_1;
319                 }
320
321                 ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
322                 ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
323
324                 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
325                                   IPU_OUTPUT_BUFFER, 0);
326                 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
327                                   IPU_OUTPUT_BUFFER, 1);
328                 ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
329                                   IPU_OUTPUT_BUFFER, 0);
330         } else {
331                 err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
332                                               IPU_OUTPUT_BUFFER,
333                                               vf_out_format, cam->win.w.width,
334                                               cam->win.w.height,
335                                               cam->win.w.width,
336                                               cam->vf_rotation,
337                                               fbi->fix.smem_start +
338                                               (fbi->fix.line_length *
339                                                fbi->var.yres),
340                                               fbi->fix.smem_start, 0, 0, 0);
341                 if (err != 0) {
342                         printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
343                         goto out_4;
344                 }
345                 ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
346                 err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
347                                       prpvf_rot_eof_callback,
348                               0, "Mxc Camera", cam);
349                 if (err < 0) {
350                         printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n");
351                         goto out_4;
352                 }
353
354                 ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
355
356                 ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
357                                   IPU_OUTPUT_BUFFER, 0);
358         }
359
360         cam->overlay_active = true;
361         return err;
362
363 out_1:
364         ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
365 out_2:
366         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP)
367                 ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
368 out_3:
369         if (cam->vf_bufs_vaddr[0]) {
370                 dma_free_coherent(0, cam->vf_bufs_size[0],
371                                   cam->vf_bufs_vaddr[0],
372                                   (dma_addr_t) cam->vf_bufs[0]);
373                 cam->vf_bufs_vaddr[0] = NULL;
374                 cam->vf_bufs[0] = 0;
375         }
376         if (cam->vf_bufs_vaddr[1]) {
377                 dma_free_coherent(0, cam->vf_bufs_size[1],
378                                   cam->vf_bufs_vaddr[1],
379                                   (dma_addr_t) cam->vf_bufs[1]);
380                 cam->vf_bufs_vaddr[1] = NULL;
381                 cam->vf_bufs[1] = 0;
382         }
383 out_4:
384         ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
385 out_5:
386         return err;
387 }
388
389 /*!
390  * prpvf_stop - stop the vf task
391  *
392  * @param private    cam_data * mxc v4l2 main structure
393  *
394  */
395 static int prpvf_stop(void *private)
396 {
397         cam_data *cam = (cam_data *) private;
398         int err = 0, i = 0;
399         struct fb_info *fbi = NULL;
400         struct fb_var_screeninfo fbvar;
401 #ifdef CONFIG_MXC_MIPI_CSI2
402         void *mipi_csi2_info;
403         int ipu_id;
404         int csi_id;
405 #endif
406
407         if (cam->overlay_active == false)
408                 return 0;
409
410         for (i = 0; i < num_registered_fb; i++) {
411                 char *idstr = registered_fb[i]->fix.id;
412                 if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
413                     ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
414                         fbi = registered_fb[i];
415                         break;
416                 }
417         }
418
419         if (fbi == NULL) {
420                 printk(KERN_ERR "DISP FG fb not found\n");
421                 return -EPERM;
422         }
423
424         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
425                 ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
426                 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam);
427         }
428         buffer_num = 0;
429
430         ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
431
432         if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
433                 ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
434                 ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
435         }
436         ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
437
438         console_lock();
439         fb_blank(fbi, FB_BLANK_POWERDOWN);
440         console_unlock();
441
442         /* Set the overlay frame buffer std to what it is used to be */
443         fbvar = fbi->var;
444         fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
445         fbvar.nonstd = cam->fb_origin_std;
446         fbvar.activate |= FB_ACTIVATE_FORCE;
447         fb_set_var(fbi, &fbvar);
448
449 #ifdef CONFIG_MXC_MIPI_CSI2
450         mipi_csi2_info = mipi_csi2_get_info();
451
452         if (mipi_csi2_info) {
453                 if (mipi_csi2_get_status(mipi_csi2_info)) {
454                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
455                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
456
457                         if (cam->ipu == ipu_get_soc(ipu_id)
458                                 && cam->csi == csi_id)
459                                 mipi_csi2_pixelclk_disable(mipi_csi2_info);
460                 }
461         } else {
462                 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
463                        __func__, __FILE__);
464                 return -EPERM;
465         }
466 #endif
467
468         if (cam->vf_bufs_vaddr[0]) {
469                 dma_free_coherent(0, cam->vf_bufs_size[0],
470                                   cam->vf_bufs_vaddr[0],
471                                   (dma_addr_t) cam->vf_bufs[0]);
472                 cam->vf_bufs_vaddr[0] = NULL;
473                 cam->vf_bufs[0] = 0;
474         }
475         if (cam->vf_bufs_vaddr[1]) {
476                 dma_free_coherent(0, cam->vf_bufs_size[1],
477                                   cam->vf_bufs_vaddr[1],
478                                   (dma_addr_t) cam->vf_bufs[1]);
479                 cam->vf_bufs_vaddr[1] = NULL;
480                 cam->vf_bufs[1] = 0;
481         }
482
483         cam->overlay_active = false;
484         return err;
485 }
486
487 /*!
488  * Enable csi
489  * @param private       struct cam_data * mxc capture instance
490  *
491  * @return  status
492  */
493 static int prp_vf_enable_csi(void *private)
494 {
495         cam_data *cam = (cam_data *) private;
496
497         return ipu_enable_csi(cam->ipu, cam->csi);
498 }
499
500 /*!
501  * Disable csi
502  * @param private       struct cam_data * mxc capture instance
503  *
504  * @return  status
505  */
506 static int prp_vf_disable_csi(void *private)
507 {
508         cam_data *cam = (cam_data *) private;
509
510         /* free csi eof irq firstly.
511          * when disable csi, wait for idmac eof.
512          * it requests eof irq again */
513         if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP)
514                 ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
515
516         return ipu_disable_csi(cam->ipu, cam->csi);
517 }
518
519 /*!
520  * function to select PRP-VF as the working path
521  *
522  * @param private    cam_data * mxc v4l2 main structure
523  *
524  * @return  status
525  */
526 int prp_vf_sdc_select(void *private)
527 {
528         cam_data *cam;
529         int err = 0;
530         if (private) {
531                 cam = (cam_data *) private;
532                 cam->vf_start_sdc = prpvf_start;
533                 cam->vf_stop_sdc = prpvf_stop;
534                 cam->vf_enable_csi = prp_vf_enable_csi;
535                 cam->vf_disable_csi = prp_vf_disable_csi;
536                 cam->overlay_active = false;
537         } else
538                 err = -EIO;
539
540         return err;
541 }
542 EXPORT_SYMBOL(prp_vf_sdc_select);
543
544 /*!
545  * function to de-select PRP-VF as the working path
546  *
547  * @param private    cam_data * mxc v4l2 main structure
548  *
549  * @return  int
550  */
551 int prp_vf_sdc_deselect(void *private)
552 {
553         cam_data *cam;
554
555         if (private) {
556                 cam = (cam_data *) private;
557                 cam->vf_start_sdc = NULL;
558                 cam->vf_stop_sdc = NULL;
559                 cam->vf_enable_csi = NULL;
560                 cam->vf_disable_csi = NULL;
561         }
562         return 0;
563 }
564 EXPORT_SYMBOL(prp_vf_sdc_deselect);
565
566 /*!
567  * Init viewfinder task.
568  *
569  * @return  Error code indicating success or failure
570  */
571 __init int prp_vf_sdc_init(void)
572 {
573         return 0;
574 }
575
576 /*!
577  * Deinit viewfinder task.
578  *
579  * @return  Error code indicating success or failure
580  */
581 void __exit prp_vf_sdc_exit(void)
582 {
583 }
584
585 module_init(prp_vf_sdc_init);
586 module_exit(prp_vf_sdc_exit);
587
588 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
589 MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
590 MODULE_LICENSE("GPL");