]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/media/platform/mxc/capture/ipu_csi_enc.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_csi_enc.c
1 /*
2  * Copyright 2009-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_csi_enc.c
16  *
17  * @brief CSI Use case for video capture
18  *
19  * @ingroup IPU
20  */
21
22 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/dma-mapping.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 #ifdef CAMERA_DBG
31         #define CAMERA_TRACE(x) (printk)x
32 #else
33         #define CAMERA_TRACE(x)
34 #endif
35
36 /*
37  * Function definitions
38  */
39
40 /*!
41  * csi ENC callback function.
42  *
43  * @param irq       int irq line
44  * @param dev_id    void * device id
45  *
46  * @return status   IRQ_HANDLED for handled
47  */
48 static irqreturn_t csi_enc_callback(int irq, void *dev_id)
49 {
50         cam_data *cam = (cam_data *) dev_id;
51
52         if (cam->enc_callback == NULL)
53                 return IRQ_HANDLED;
54
55         cam->enc_callback(irq, dev_id);
56         return IRQ_HANDLED;
57 }
58
59 /*!
60  * CSI ENC enable channel setup function
61  *
62  * @param cam       struct cam_data * mxc capture instance
63  *
64  * @return  status
65  */
66 static int csi_enc_setup(cam_data *cam)
67 {
68         ipu_channel_params_t params;
69         u32 pixel_fmt;
70         int err = 0, sensor_protocol = 0;
71         dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
72 #ifdef CONFIG_MXC_MIPI_CSI2
73         void *mipi_csi2_info;
74         int ipu_id;
75         int csi_id;
76 #endif
77
78         CAMERA_TRACE("In csi_enc_setup\n");
79         if (!cam) {
80                 printk(KERN_ERR "cam private is NULL\n");
81                 return -ENXIO;
82         }
83
84         memset(&params, 0, sizeof(ipu_channel_params_t));
85         params.csi_mem.csi = cam->csi;
86
87         sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
88         switch (sensor_protocol) {
89         case IPU_CSI_CLK_MODE_GATED_CLK:
90         case IPU_CSI_CLK_MODE_NONGATED_CLK:
91         case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
92         case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
93         case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
94                 params.csi_mem.interlaced = false;
95                 break;
96         case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
97         case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
98         case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
99                 params.csi_mem.interlaced = true;
100                 break;
101         default:
102                 printk(KERN_ERR "sensor protocol unsupported\n");
103                 return -EINVAL;
104         }
105
106         if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
107                 pixel_fmt = IPU_PIX_FMT_YUV420P;
108         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420)
109                 pixel_fmt = IPU_PIX_FMT_YVU420P;
110         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
111                 pixel_fmt = IPU_PIX_FMT_YUV422P;
112         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
113                 pixel_fmt = IPU_PIX_FMT_UYVY;
114         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
115                 pixel_fmt = IPU_PIX_FMT_YUYV;
116         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
117                 pixel_fmt = IPU_PIX_FMT_NV12;
118         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
119                 pixel_fmt = IPU_PIX_FMT_BGR24;
120         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
121                 pixel_fmt = IPU_PIX_FMT_RGB24;
122         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
123                 pixel_fmt = IPU_PIX_FMT_RGB565;
124         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
125                 pixel_fmt = IPU_PIX_FMT_BGR32;
126         else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
127                 pixel_fmt = IPU_PIX_FMT_RGB32;
128         else {
129                 printk(KERN_ERR "format not supported\n");
130                 return -EINVAL;
131         }
132
133 #ifdef CONFIG_MXC_MIPI_CSI2
134         mipi_csi2_info = mipi_csi2_get_info();
135
136         if (mipi_csi2_info) {
137                 if (mipi_csi2_get_status(mipi_csi2_info)) {
138                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
139                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
140
141                         if (cam->ipu == ipu_get_soc(ipu_id)
142                                 && cam->csi == csi_id) {
143                                 params.csi_mem.mipi_en = true;
144                                 params.csi_mem.mipi_vc =
145                                 mipi_csi2_get_virtual_channel(mipi_csi2_info);
146                                 params.csi_mem.mipi_id =
147                                 mipi_csi2_get_datatype(mipi_csi2_info);
148
149                                 mipi_csi2_pixelclk_enable(mipi_csi2_info);
150                         } else {
151                                 params.csi_mem.mipi_en = false;
152                                 params.csi_mem.mipi_vc = 0;
153                                 params.csi_mem.mipi_id = 0;
154                         }
155                 } else {
156                         params.csi_mem.mipi_en = false;
157                         params.csi_mem.mipi_vc = 0;
158                         params.csi_mem.mipi_id = 0;
159                 }
160         }
161 #endif
162
163         err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
164         if (err != 0) {
165                 printk(KERN_ERR "ipu_init_channel %d\n", err);
166                 return err;
167         }
168
169         err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
170                                       pixel_fmt, cam->v2f.fmt.pix.width,
171                                       cam->v2f.fmt.pix.height,
172                                       cam->v2f.fmt.pix.bytesperline,
173                                       IPU_ROTATE_NONE,
174                                       dummy, dummy, 0,
175                                       cam->offset.u_offset,
176                                       cam->offset.v_offset);
177         if (err != 0) {
178                 printk(KERN_ERR "CSI_MEM output buffer\n");
179                 return err;
180         }
181         err = ipu_enable_channel(cam->ipu, CSI_MEM);
182         if (err < 0) {
183                 printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
184                 return err;
185         }
186
187         return err;
188 }
189
190 /*!
191  * function to update physical buffer address for encorder IDMA channel
192  *
193  * @param eba         physical buffer address for encorder IDMA channel
194  * @param buffer_num  int buffer 0 or buffer 1
195  *
196  * @return  status
197  */
198 static int csi_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba,
199                               int *buffer_num)
200 {
201         int err = 0;
202
203         pr_debug("eba %x\n", eba);
204         err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
205                                         *buffer_num, eba);
206         if (err != 0) {
207                 ipu_clear_buffer_ready(ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
208                                        *buffer_num);
209
210                 err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
211                                                 *buffer_num, eba);
212                 if (err != 0) {
213                         pr_err("ERROR: v4l2 capture: fail to update "
214                                "buf%d\n", *buffer_num);
215                         return err;
216                 }
217         }
218
219         ipu_select_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num);
220
221         *buffer_num = (*buffer_num == 0) ? 1 : 0;
222
223         return 0;
224 }
225
226 /*!
227  * Enable encoder task
228  * @param private       struct cam_data * mxc capture instance
229  *
230  * @return  status
231  */
232 static int csi_enc_enabling_tasks(void *private)
233 {
234         cam_data *cam = (cam_data *) private;
235         int err = 0;
236         CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
237
238         cam->dummy_frame.vaddress = dma_alloc_coherent(0,
239                                PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
240                                &cam->dummy_frame.paddress,
241                                GFP_DMA | GFP_KERNEL);
242         if (cam->dummy_frame.vaddress == 0) {
243                 pr_err("ERROR: v4l2 capture: Allocate dummy frame "
244                        "failed.\n");
245                 return -ENOBUFS;
246         }
247         cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
248         cam->dummy_frame.buffer.length =
249             PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
250         cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
251
252         ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
253         err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
254                               csi_enc_callback, 0, "Mxc Camera", cam);
255         if (err != 0) {
256                 printk(KERN_ERR "Error registering rot irq\n");
257                 return err;
258         }
259
260         err = csi_enc_setup(cam);
261         if (err != 0) {
262                 printk(KERN_ERR "csi_enc_setup %d\n", err);
263                 return err;
264         }
265
266         return err;
267 }
268
269 /*!
270  * Disable encoder task
271  * @param private       struct cam_data * mxc capture instance
272  *
273  * @return  int
274  */
275 static int csi_enc_disabling_tasks(void *private)
276 {
277         cam_data *cam = (cam_data *) private;
278         int err = 0;
279 #ifdef CONFIG_MXC_MIPI_CSI2
280         void *mipi_csi2_info;
281         int ipu_id;
282         int csi_id;
283 #endif
284
285         err = ipu_disable_channel(cam->ipu, CSI_MEM, true);
286
287         ipu_uninit_channel(cam->ipu, CSI_MEM);
288
289         if (cam->dummy_frame.vaddress != 0) {
290                 dma_free_coherent(0, cam->dummy_frame.buffer.length,
291                                   cam->dummy_frame.vaddress,
292                                   cam->dummy_frame.paddress);
293                 cam->dummy_frame.vaddress = 0;
294         }
295
296 #ifdef CONFIG_MXC_MIPI_CSI2
297         mipi_csi2_info = mipi_csi2_get_info();
298
299         if (mipi_csi2_info) {
300                 if (mipi_csi2_get_status(mipi_csi2_info)) {
301                         ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
302                         csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
303
304                         if (cam->ipu == ipu_get_soc(ipu_id)
305                                 && cam->csi == csi_id)
306                                 mipi_csi2_pixelclk_disable(mipi_csi2_info);
307                 }
308         }
309 #endif
310
311         return err;
312 }
313
314 /*!
315  * Enable csi
316  * @param private       struct cam_data * mxc capture instance
317  *
318  * @return  status
319  */
320 static int csi_enc_enable_csi(void *private)
321 {
322         cam_data *cam = (cam_data *) private;
323
324         return ipu_enable_csi(cam->ipu, cam->csi);
325 }
326
327 /*!
328  * Disable csi
329  * @param private       struct cam_data * mxc capture instance
330  *
331  * @return  status
332  */
333 static int csi_enc_disable_csi(void *private)
334 {
335         cam_data *cam = (cam_data *) private;
336
337         /* free csi eof irq firstly.
338          * when disable csi, wait for idmac eof.
339          * it requests eof irq again */
340         ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
341
342         return ipu_disable_csi(cam->ipu, cam->csi);
343 }
344
345 /*!
346  * function to select CSI ENC as the working path
347  *
348  * @param private       struct cam_data * mxc capture instance
349  *
350  * @return  int
351  */
352 int csi_enc_select(void *private)
353 {
354         cam_data *cam = (cam_data *) private;
355         int err = 0;
356
357         if (cam) {
358                 cam->enc_update_eba = csi_enc_eba_update;
359                 cam->enc_enable = csi_enc_enabling_tasks;
360                 cam->enc_disable = csi_enc_disabling_tasks;
361                 cam->enc_enable_csi = csi_enc_enable_csi;
362                 cam->enc_disable_csi = csi_enc_disable_csi;
363         } else {
364                 err = -EIO;
365         }
366
367         return err;
368 }
369 EXPORT_SYMBOL(csi_enc_select);
370
371 /*!
372  * function to de-select CSI ENC as the working path
373  *
374  * @param private       struct cam_data * mxc capture instance
375  *
376  * @return  int
377  */
378 int csi_enc_deselect(void *private)
379 {
380         cam_data *cam = (cam_data *) private;
381         int err = 0;
382
383         if (cam) {
384                 cam->enc_update_eba = NULL;
385                 cam->enc_enable = NULL;
386                 cam->enc_disable = NULL;
387                 cam->enc_enable_csi = NULL;
388                 cam->enc_disable_csi = NULL;
389         }
390
391         return err;
392 }
393 EXPORT_SYMBOL(csi_enc_deselect);
394
395 /*!
396  * Init the Encorder channels
397  *
398  * @return  Error code indicating success or failure
399  */
400 __init int csi_enc_init(void)
401 {
402         return 0;
403 }
404
405 /*!
406  * Deinit the Encorder channels
407  *
408  */
409 void __exit csi_enc_exit(void)
410 {
411 }
412
413 module_init(csi_enc_init);
414 module_exit(csi_enc_exit);
415
416 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
417 MODULE_DESCRIPTION("CSI ENC Driver");
418 MODULE_LICENSE("GPL");