]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c
ad5e1c860e01f03e3a693cc588c9b581b4efea43
[karo-tx-linux.git] / drivers / media / platform / mxc / capture / ipu_bg_overlay_sdc.c
1
2 /*
3  * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
4  */
5
6 /*
7  * The code contained herein is licensed under the GNU General Public
8  * License. You may obtain a copy of the GNU General Public License
9  * Version 2 or later at the following locations:
10  *
11  * http://www.opensource.org/licenses/gpl-license.html
12  * http://www.gnu.org/copyleft/gpl.html
13  */
14
15 /*!
16  * @file ipu_bg_overlay_sdc_bg.c
17  *
18  * @brief IPU Use case for PRP-VF back-ground
19  *
20  * @ingroup IPU
21  */
22 #include <linux/module.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/fb.h>
25 #include <linux/ipu.h>
26 #include <linux/mipi_csi2.h>
27 #include "mxc_v4l2_capture.h"
28 #include "ipu_prp_sw.h"
29
30 static int csi_buffer_num;
31 static u32 bpp, csi_mem_bufsize = 3;
32 static u32 out_format;
33 static struct ipu_soc *disp_ipu;
34 static u32 offset;
35
36 static void csi_buf_work_func(struct work_struct *work)
37 {
38         int err = 0;
39         cam_data *cam =
40                 container_of(work, struct _cam_data, csi_work_struct);
41
42         struct ipu_task task;
43         memset(&task, 0, sizeof(task));
44
45         if (csi_buffer_num)
46                 task.input.paddr = cam->vf_bufs[0];
47         else
48                 task.input.paddr = cam->vf_bufs[1];
49         task.input.width = cam->crop_current.width;
50         task.input.height = cam->crop_current.height;
51         task.input.format = IPU_PIX_FMT_UYVY;
52
53         task.output.paddr = offset;
54         task.output.width = cam->overlay_fb->var.xres;
55         task.output.height = cam->overlay_fb->var.yres;
56         task.output.format = out_format;
57         task.output.rotate = cam->rotation;
58         task.output.crop.pos.x = cam->win.w.left;
59         task.output.crop.pos.y = cam->win.w.top;
60         if (cam->win.w.width > 1024 || cam->win.w.height > 1024) {
61                 task.output.crop.w = cam->overlay_fb->var.xres;
62                 task.output.crop.h = cam->overlay_fb->var.yres;
63         } else {
64                 task.output.crop.w = cam->win.w.width;
65                 task.output.crop.h = cam->win.w.height;
66         }
67 again:
68         err = ipu_check_task(&task);
69         if (err != IPU_CHECK_OK) {
70                 if (err > IPU_CHECK_ERR_MIN) {
71                         if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
72                                 task.input.crop.w -= 8;
73                                 goto again;
74                         }
75                         if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
76                                 task.input.crop.h -= 8;
77                                 goto again;
78                         }
79                         if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
80                                         task.output.width -= 8;
81                                         task.output.crop.w = task.output.width;
82                                 goto again;
83                         }
84                         if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
85                                         task.output.height -= 8;
86                                         task.output.crop.h = task.output.height;
87                                 goto again;
88                         }
89                         printk(KERN_ERR "check ipu taks fail\n");
90                         return;
91                 }
92                 printk(KERN_ERR "check ipu taks fail\n");
93                 return;
94         }
95         err = ipu_queue_task(&task);
96         if (err < 0)
97                 printk(KERN_ERR "queue ipu task error\n");
98 }
99
100 static void get_disp_ipu(cam_data *cam)
101 {
102         if (cam->output > 2)
103                 disp_ipu = ipu_get_soc(1); /* using DISP4 */
104         else
105                 disp_ipu = ipu_get_soc(0);
106 }
107
108
109 /*!
110  * csi ENC callback function.
111  *
112  * @param irq       int irq line
113  * @param dev_id    void * device id
114  *
115  * @return status   IRQ_HANDLED for handled
116  */
117 static irqreturn_t csi_enc_callback(int irq, void *dev_id)
118 {
119         cam_data *cam = (cam_data *) dev_id;
120
121         ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, csi_buffer_num);
122         schedule_work(&cam->csi_work_struct);
123         csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
124         return IRQ_HANDLED;
125 }
126
127 static int csi_enc_setup(cam_data *cam)
128 {
129         ipu_channel_params_t params;
130         u32 pixel_fmt;
131         int err = 0, sensor_protocol = 0;
132 #ifdef CONFIG_MXC_MIPI_CSI2
133         void *mipi_csi2_info;
134         int ipu_id;
135         int csi_id;
136 #endif
137
138         if (!cam) {
139                 printk(KERN_ERR "cam private is NULL\n");
140                 return -ENXIO;
141         }
142
143         memset(&params, 0, sizeof(ipu_channel_params_t));
144         params.csi_mem.csi = cam->csi;
145
146         sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
147         switch (sensor_protocol) {
148         case IPU_CSI_CLK_MODE_GATED_CLK:
149         case IPU_CSI_CLK_MODE_NONGATED_CLK:
150         case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
151         case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
152         case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
153                 params.csi_mem.interlaced = false;
154                 break;
155         case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
156         case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
157         case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
158                 params.csi_mem.interlaced = true;
159                 break;
160         default:
161                 printk(KERN_ERR "sensor protocol unsupported\n");
162                 return -EINVAL;
163         }
164
165 #ifdef CONFIG_MXC_MIPI_CSI2
166         mipi_csi2_info = mipi_csi2_get_info();
167
168         if (mipi_csi2_info) {
169                 if (mipi_csi2_get_status(mipi_csi2_info)) {
170                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
171                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
172
173                         if (cam->ipu == ipu_get_soc(ipu_id)
174                                 && cam->csi == csi_id) {
175                                 params.csi_mem.mipi_en = true;
176                                 params.csi_mem.mipi_vc =
177                                 mipi_csi2_get_virtual_channel(mipi_csi2_info);
178                                 params.csi_mem.mipi_id =
179                                 mipi_csi2_get_datatype(mipi_csi2_info);
180
181                                 mipi_csi2_pixelclk_enable(mipi_csi2_info);
182                         } else {
183                                 params.csi_mem.mipi_en = false;
184                                 params.csi_mem.mipi_vc = 0;
185                                 params.csi_mem.mipi_id = 0;
186                         }
187                 } else {
188                         params.csi_mem.mipi_en = false;
189                         params.csi_mem.mipi_vc = 0;
190                         params.csi_mem.mipi_id = 0;
191                 }
192         } else {
193                 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
194                        __func__, __FILE__);
195                 return -EPERM;
196         }
197 #endif
198
199         if (cam->vf_bufs_vaddr[0]) {
200                 dma_free_coherent(0, cam->vf_bufs_size[0],
201                                   cam->vf_bufs_vaddr[0],
202                                   (dma_addr_t) cam->vf_bufs[0]);
203         }
204         if (cam->vf_bufs_vaddr[1]) {
205                 dma_free_coherent(0, cam->vf_bufs_size[1],
206                                   cam->vf_bufs_vaddr[1],
207                                   (dma_addr_t) cam->vf_bufs[1]);
208         }
209         csi_mem_bufsize =
210                 cam->crop_current.width * cam->crop_current.height * 2;
211         cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
212         cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
213                                                            cam->vf_bufs_size[0],
214                                                            (dma_addr_t *) &
215                                                            cam->vf_bufs[0],
216                                                            GFP_DMA |
217                                                            GFP_KERNEL);
218         if (cam->vf_bufs_vaddr[0] == NULL) {
219                 printk(KERN_ERR "Error to allocate vf buffer\n");
220                 err = -ENOMEM;
221                 goto out_2;
222         }
223         cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
224         cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
225                                                            cam->vf_bufs_size[1],
226                                                            (dma_addr_t *) &
227                                                            cam->vf_bufs[1],
228                                                            GFP_DMA |
229                                                            GFP_KERNEL);
230         if (cam->vf_bufs_vaddr[1] == NULL) {
231                 printk(KERN_ERR "Error to allocate vf buffer\n");
232                 err = -ENOMEM;
233                 goto out_1;
234         }
235         pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
236
237         err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
238         if (err != 0) {
239                 printk(KERN_ERR "ipu_init_channel %d\n", err);
240                 goto out_1;
241         }
242
243         pixel_fmt = IPU_PIX_FMT_UYVY;
244         err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
245                                 pixel_fmt, cam->crop_current.width,
246                                 cam->crop_current.height,
247                                 cam->crop_current.width, IPU_ROTATE_NONE,
248                                 cam->vf_bufs[0], cam->vf_bufs[1], 0,
249                                 cam->offset.u_offset, cam->offset.u_offset);
250         if (err != 0) {
251                 printk(KERN_ERR "CSI_MEM output buffer\n");
252                 goto out_1;
253         }
254         err = ipu_enable_channel(cam->ipu, CSI_MEM);
255         if (err < 0) {
256                 printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
257                 goto out_1;
258         }
259
260         csi_buffer_num = 0;
261
262         ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
263         ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 1);
264         return err;
265 out_1:
266         if (cam->vf_bufs_vaddr[0]) {
267                 dma_free_coherent(0, cam->vf_bufs_size[0],
268                                   cam->vf_bufs_vaddr[0],
269                                   (dma_addr_t) cam->vf_bufs[0]);
270                 cam->vf_bufs_vaddr[0] = NULL;
271                 cam->vf_bufs[0] = 0;
272         }
273         if (cam->vf_bufs_vaddr[1]) {
274                 dma_free_coherent(0, cam->vf_bufs_size[1],
275                                   cam->vf_bufs_vaddr[1],
276                                   (dma_addr_t) cam->vf_bufs[1]);
277                 cam->vf_bufs_vaddr[1] = NULL;
278                 cam->vf_bufs[1] = 0;
279         }
280 out_2:
281         return err;
282 }
283
284 /*!
285  * Enable encoder task
286  * @param private       struct cam_data * mxc capture instance
287  *
288  * @return  status
289  */
290 static int csi_enc_enabling_tasks(void *private)
291 {
292         cam_data *cam = (cam_data *) private;
293         int err = 0;
294
295         ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
296         err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
297                               csi_enc_callback, 0, "Mxc Camera", cam);
298         if (err != 0) {
299                 printk(KERN_ERR "Error registering CSI0_OUT_EOF irq\n");
300                 return err;
301         }
302
303         INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
304
305         err = csi_enc_setup(cam);
306         if (err != 0) {
307                 printk(KERN_ERR "csi_enc_setup %d\n", err);
308                 goto out1;
309         }
310
311         return err;
312 out1:
313         ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
314         return err;
315 }
316
317 /*!
318  * bg_overlay_start - start the overlay task
319  *
320  * @param private    cam_data * mxc v4l2 main structure
321  *
322  */
323 static int bg_overlay_start(void *private)
324 {
325         cam_data *cam = (cam_data *) private;
326         int err = 0;
327
328         if (!cam) {
329                 printk(KERN_ERR "private is NULL\n");
330                 return -EIO;
331         }
332
333         if (cam->overlay_active == true) {
334                 pr_debug("already start.\n");
335                 return 0;
336         }
337
338         get_disp_ipu(cam);
339
340         out_format = cam->v4l2_fb.fmt.pixelformat;
341         if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
342                 bpp = 3, csi_mem_bufsize = 3;
343                 pr_info("BGR24\n");
344         } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
345                 bpp = 2, csi_mem_bufsize = 2;
346                 pr_info("RGB565\n");
347         } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
348                 bpp = 4, csi_mem_bufsize = 4;
349                 pr_info("BGR32\n");
350         } else {
351                 printk(KERN_ERR
352                        "unsupported fix format from the framebuffer.\n");
353                 return -EINVAL;
354         }
355
356         offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
357             csi_mem_bufsize * cam->win.w.left;
358
359         if (cam->v4l2_fb.base == 0)
360                 printk(KERN_ERR "invalid frame buffer address.\n");
361         else
362                 offset += (u32) cam->v4l2_fb.base;
363
364         csi_mem_bufsize = cam->win.w.width * cam->win.w.height
365                                 * csi_mem_bufsize;
366
367         err = csi_enc_enabling_tasks(cam);
368         if (err != 0) {
369                 printk(KERN_ERR "Error csi enc enable fail\n");
370                 return err;
371         }
372
373         cam->overlay_active = true;
374         return err;
375 }
376
377 /*!
378  * bg_overlay_stop - stop the overlay task
379  *
380  * @param private    cam_data * mxc v4l2 main structure
381  *
382  */
383 static int bg_overlay_stop(void *private)
384 {
385         int err = 0;
386         cam_data *cam = (cam_data *) private;
387 #ifdef CONFIG_MXC_MIPI_CSI2
388         void *mipi_csi2_info;
389         int ipu_id;
390         int csi_id;
391 #endif
392
393         if (cam->overlay_active == false)
394                 return 0;
395
396         err = ipu_disable_channel(cam->ipu, CSI_MEM, true);
397
398         ipu_uninit_channel(cam->ipu, CSI_MEM);
399
400         csi_buffer_num = 0;
401
402 #ifdef CONFIG_MXC_MIPI_CSI2
403         mipi_csi2_info = mipi_csi2_get_info();
404
405         if (mipi_csi2_info) {
406                 if (mipi_csi2_get_status(mipi_csi2_info)) {
407                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
408                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
409
410                         if (cam->ipu == ipu_get_soc(ipu_id)
411                                 && cam->csi == csi_id)
412                                 mipi_csi2_pixelclk_disable(mipi_csi2_info);
413                 }
414         } else {
415                 printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
416                        __func__, __FILE__);
417                 return -EPERM;
418         }
419 #endif
420
421         flush_work(&cam->csi_work_struct);
422         cancel_work_sync(&cam->csi_work_struct);
423
424         if (cam->vf_bufs_vaddr[0]) {
425                 dma_free_coherent(0, cam->vf_bufs_size[0],
426                                   cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
427                 cam->vf_bufs_vaddr[0] = NULL;
428                 cam->vf_bufs[0] = 0;
429         }
430         if (cam->vf_bufs_vaddr[1]) {
431                 dma_free_coherent(0, cam->vf_bufs_size[1],
432                                   cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
433                 cam->vf_bufs_vaddr[1] = NULL;
434                 cam->vf_bufs[1] = 0;
435         }
436         if (cam->rot_vf_bufs_vaddr[0]) {
437                 dma_free_coherent(0, cam->rot_vf_buf_size[0],
438                                   cam->rot_vf_bufs_vaddr[0],
439                                   cam->rot_vf_bufs[0]);
440                 cam->rot_vf_bufs_vaddr[0] = NULL;
441                 cam->rot_vf_bufs[0] = 0;
442         }
443         if (cam->rot_vf_bufs_vaddr[1]) {
444                 dma_free_coherent(0, cam->rot_vf_buf_size[1],
445                                   cam->rot_vf_bufs_vaddr[1],
446                                   cam->rot_vf_bufs[1]);
447                 cam->rot_vf_bufs_vaddr[1] = NULL;
448                 cam->rot_vf_bufs[1] = 0;
449         }
450
451         cam->overlay_active = false;
452         return err;
453 }
454
455 /*!
456  * Enable csi
457  * @param private       struct cam_data * mxc capture instance
458  *
459  * @return  status
460  */
461 static int bg_overlay_enable_csi(void *private)
462 {
463         cam_data *cam = (cam_data *) private;
464
465         return ipu_enable_csi(cam->ipu, cam->csi);
466 }
467
468 /*!
469  * Disable csi
470  * @param private       struct cam_data * mxc capture instance
471  *
472  * @return  status
473  */
474 static int bg_overlay_disable_csi(void *private)
475 {
476         cam_data *cam = (cam_data *) private;
477
478         /* free csi eof irq firstly.
479          * when disable csi, wait for idmac eof.
480          * it requests eof irq again */
481         ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
482
483         return ipu_disable_csi(cam->ipu, cam->csi);
484 }
485
486 /*!
487  * function to select bg as the working path
488  *
489  * @param private    cam_data * mxc v4l2 main structure
490  *
491  * @return  status
492  */
493 int bg_overlay_sdc_select(void *private)
494 {
495         cam_data *cam = (cam_data *) private;
496
497         if (cam) {
498                 cam->vf_start_sdc = bg_overlay_start;
499                 cam->vf_stop_sdc = bg_overlay_stop;
500                 cam->vf_enable_csi = bg_overlay_enable_csi;
501                 cam->vf_disable_csi = bg_overlay_disable_csi;
502                 cam->overlay_active = false;
503         }
504
505         return 0;
506 }
507 EXPORT_SYMBOL(bg_overlay_sdc_select);
508
509 /*!
510  * function to de-select bg as the working path
511  *
512  * @param private    cam_data * mxc v4l2 main structure
513  *
514  * @return  status
515  */
516 int bg_overlay_sdc_deselect(void *private)
517 {
518         cam_data *cam = (cam_data *) private;
519
520         if (cam) {
521                 cam->vf_start_sdc = NULL;
522                 cam->vf_stop_sdc = NULL;
523                 cam->vf_enable_csi = NULL;
524                 cam->vf_disable_csi = NULL;
525         }
526         return 0;
527 }
528 EXPORT_SYMBOL(bg_overlay_sdc_deselect);
529
530 /*!
531  * Init background overlay task.
532  *
533  * @return  Error code indicating success or failure
534  */
535 __init int bg_overlay_sdc_init(void)
536 {
537         return 0;
538 }
539
540 /*!
541  * Deinit background overlay task.
542  *
543  * @return  Error code indicating success or failure
544  */
545 void __exit bg_overlay_sdc_exit(void)
546 {
547 }
548
549 module_init(bg_overlay_sdc_init);
550 module_exit(bg_overlay_sdc_exit);
551
552 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
553 MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
554 MODULE_LICENSE("GPL");