]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/mxc/ipu3/ipu_ic.c
2da79dfed287d7e45f62daa9810bf86f042c9cee
[karo-tx-linux.git] / drivers / mxc / ipu3 / ipu_ic.c
1 /*
2  * Copyright 2005-2013 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_ic.c
16  *
17  * @brief IPU IC functions
18  *
19  * @ingroup IPU
20  */
21 #include <linux/errno.h>
22 #include <linux/init.h>
23 #include <linux/io.h>
24 #include <linux/ipu-v3.h>
25 #include <linux/spinlock.h>
26 #include <linux/types.h>
27 #include <linux/videodev2.h>
28
29 #include "ipu_param_mem.h"
30 #include "ipu_regs.h"
31
32 enum {
33         IC_TASK_VIEWFINDER,
34         IC_TASK_ENCODER,
35         IC_TASK_POST_PROCESSOR
36 };
37
38 static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
39                       ipu_color_space_t out_format, int csc_index);
40
41 static int _calc_resize_coeffs(struct ipu_soc *ipu,
42                                 uint32_t inSize, uint32_t outSize,
43                                 uint32_t *resizeCoeff,
44                                 uint32_t *downsizeCoeff);
45
46 void _ipu_vdi_set_top_field_man(struct ipu_soc *ipu, bool top_field_0)
47 {
48         uint32_t reg;
49
50         reg = ipu_vdi_read(ipu, VDI_C);
51         if (top_field_0)
52                 reg &= ~VDI_C_TOP_FIELD_MAN_1;
53         else
54                 reg |= VDI_C_TOP_FIELD_MAN_1;
55         ipu_vdi_write(ipu, reg, VDI_C);
56 }
57
58 void _ipu_vdi_set_motion(struct ipu_soc *ipu, ipu_motion_sel motion_sel)
59 {
60         uint32_t reg;
61
62         reg = ipu_vdi_read(ipu, VDI_C);
63         reg &= ~(VDI_C_MOT_SEL_FULL | VDI_C_MOT_SEL_MED | VDI_C_MOT_SEL_LOW);
64         if (motion_sel == HIGH_MOTION)
65                 reg |= VDI_C_MOT_SEL_FULL;
66         else if (motion_sel == MED_MOTION)
67                 reg |= VDI_C_MOT_SEL_MED;
68         else
69                 reg |= VDI_C_MOT_SEL_LOW;
70
71         ipu_vdi_write(ipu, reg, VDI_C);
72         dev_dbg(ipu->dev, "VDI_C = \t0x%08X\n", reg);
73 }
74
75 void ic_dump_register(struct ipu_soc *ipu)
76 {
77         printk(KERN_DEBUG "IC_CONF = \t0x%08X\n", ipu_ic_read(ipu, IC_CONF));
78         printk(KERN_DEBUG "IC_PRP_ENC_RSC = \t0x%08X\n",
79                ipu_ic_read(ipu, IC_PRP_ENC_RSC));
80         printk(KERN_DEBUG "IC_PRP_VF_RSC = \t0x%08X\n",
81                ipu_ic_read(ipu, IC_PRP_VF_RSC));
82         printk(KERN_DEBUG "IC_PP_RSC = \t0x%08X\n", ipu_ic_read(ipu, IC_PP_RSC));
83         printk(KERN_DEBUG "IC_IDMAC_1 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_1));
84         printk(KERN_DEBUG "IC_IDMAC_2 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_2));
85         printk(KERN_DEBUG "IC_IDMAC_3 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_3));
86 }
87
88 void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel)
89 {
90         uint32_t ic_conf;
91
92         ic_conf = ipu_ic_read(ipu, IC_CONF);
93         switch (channel) {
94         case CSI_PRP_VF_MEM:
95         case MEM_PRP_VF_MEM:
96                 ic_conf |= IC_CONF_PRPVF_EN;
97                 break;
98         case MEM_VDI_PRP_VF_MEM:
99                 ic_conf |= IC_CONF_PRPVF_EN;
100                 break;
101         case MEM_VDI_MEM:
102                 ic_conf |= IC_CONF_PRPVF_EN | IC_CONF_RWS_EN ;
103                 break;
104         case MEM_ROT_VF_MEM:
105                 ic_conf |= IC_CONF_PRPVF_ROT_EN;
106                 break;
107         case CSI_PRP_ENC_MEM:
108         case MEM_PRP_ENC_MEM:
109                 ic_conf |= IC_CONF_PRPENC_EN;
110                 break;
111         case MEM_ROT_ENC_MEM:
112                 ic_conf |= IC_CONF_PRPENC_ROT_EN;
113                 break;
114         case MEM_PP_MEM:
115                 ic_conf |= IC_CONF_PP_EN;
116                 break;
117         case MEM_ROT_PP_MEM:
118                 ic_conf |= IC_CONF_PP_ROT_EN;
119                 break;
120         default:
121                 break;
122         }
123         ipu_ic_write(ipu, ic_conf, IC_CONF);
124 }
125
126 void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel)
127 {
128         uint32_t ic_conf;
129
130         ic_conf = ipu_ic_read(ipu, IC_CONF);
131         switch (channel) {
132         case CSI_PRP_VF_MEM:
133         case MEM_PRP_VF_MEM:
134                 ic_conf &= ~IC_CONF_PRPVF_EN;
135                 break;
136         case MEM_VDI_PRP_VF_MEM:
137                 ic_conf &= ~IC_CONF_PRPVF_EN;
138                 break;
139         case MEM_VDI_MEM:
140                 ic_conf &= ~(IC_CONF_PRPVF_EN | IC_CONF_RWS_EN);
141                 break;
142         case MEM_ROT_VF_MEM:
143                 ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
144                 break;
145         case CSI_PRP_ENC_MEM:
146         case MEM_PRP_ENC_MEM:
147                 ic_conf &= ~IC_CONF_PRPENC_EN;
148                 break;
149         case MEM_ROT_ENC_MEM:
150                 ic_conf &= ~IC_CONF_PRPENC_ROT_EN;
151                 break;
152         case MEM_PP_MEM:
153                 ic_conf &= ~IC_CONF_PP_EN;
154                 break;
155         case MEM_ROT_PP_MEM:
156                 ic_conf &= ~IC_CONF_PP_ROT_EN;
157                 break;
158         default:
159                 break;
160         }
161         ipu_ic_write(ipu, ic_conf, IC_CONF);
162 }
163
164 void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
165 {
166         uint32_t reg;
167         uint32_t pixel_fmt;
168         uint32_t pix_per_burst;
169
170         reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
171           (params->mem_prp_vf_mem.in_width-1);
172         ipu_vdi_write(ipu, reg, VDI_FSIZE);
173
174         /* Full motion, only vertical filter is used
175            Burst size is 4 accesses */
176         if (params->mem_prp_vf_mem.in_pixel_fmt ==
177              IPU_PIX_FMT_UYVY ||
178              params->mem_prp_vf_mem.in_pixel_fmt ==
179              IPU_PIX_FMT_YUYV) {
180                 pixel_fmt = VDI_C_CH_422;
181                 pix_per_burst = 32;
182          } else {
183                 pixel_fmt = VDI_C_CH_420;
184                 pix_per_burst = 64;
185         }
186
187         reg = ipu_vdi_read(ipu, VDI_C);
188         reg |= pixel_fmt;
189         switch (channel) {
190         case MEM_VDI_PRP_VF_MEM:
191                 reg |= VDI_C_BURST_SIZE2_4;
192                 break;
193         case MEM_VDI_PRP_VF_MEM_P:
194                 reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_SET_1 | VDI_C_VWM1_CLR_2;
195                 break;
196         case MEM_VDI_PRP_VF_MEM_N:
197                 reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
198                 break;
199
200         case MEM_VDI_MEM:
201                 reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
202                                 << VDI_C_BURST_SIZE2_OFFSET;
203                 break;
204         case MEM_VDI_MEM_P:
205                 reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
206                                 << VDI_C_BURST_SIZE1_OFFSET;
207                 reg |= VDI_C_VWM1_SET_2 | VDI_C_VWM1_CLR_2;
208                 break;
209         case MEM_VDI_MEM_N:
210                 reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
211                                 << VDI_C_BURST_SIZE3_OFFSET;
212                 reg |= VDI_C_VWM3_SET_2 | VDI_C_VWM3_CLR_2;
213                 break;
214         default:
215                 break;
216         }
217         ipu_vdi_write(ipu, reg, VDI_C);
218
219         if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_TOP)
220                 _ipu_vdi_set_top_field_man(ipu, true);
221         else if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_BOTTOM)
222                 _ipu_vdi_set_top_field_man(ipu, false);
223
224         _ipu_vdi_set_motion(ipu, params->mem_prp_vf_mem.motion_sel);
225
226         reg = ipu_ic_read(ipu, IC_CONF);
227         reg &= ~IC_CONF_RWS_EN;
228         ipu_ic_write(ipu, reg, IC_CONF);
229 }
230
231 void _ipu_vdi_uninit(struct ipu_soc *ipu)
232 {
233         ipu_vdi_write(ipu, 0, VDI_FSIZE);
234         ipu_vdi_write(ipu, 0, VDI_C);
235 }
236
237 int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
238                        bool src_is_csi)
239 {
240         uint32_t reg, ic_conf;
241         uint32_t downsizeCoeff, resizeCoeff;
242         ipu_color_space_t in_fmt, out_fmt;
243         int ret = 0;
244
245         /* Setup vertical resizing */
246         if (!params->mem_prp_vf_mem.outv_resize_ratio) {
247                 ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
248                                         params->mem_prp_vf_mem.out_height,
249                                         &resizeCoeff, &downsizeCoeff);
250                 if (ret < 0) {
251                         dev_err(ipu->dev, "failed to calculate prpvf height "
252                                 "scaling coefficients\n");
253                         return ret;
254                 }
255
256                 reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
257         } else
258                 reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
259
260         /* Setup horizontal resizing */
261         if (!params->mem_prp_vf_mem.outh_resize_ratio) {
262                 ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
263                                         params->mem_prp_vf_mem.out_width,
264                                         &resizeCoeff, &downsizeCoeff);
265                 if (ret < 0) {
266                         dev_err(ipu->dev, "failed to calculate prpvf width "
267                                 "scaling coefficients\n");
268                         return ret;
269                 }
270
271                 reg |= (downsizeCoeff << 14) | resizeCoeff;
272         } else
273                 reg |= params->mem_prp_vf_mem.outh_resize_ratio;
274
275         ipu_ic_write(ipu, reg, IC_PRP_VF_RSC);
276
277         ic_conf = ipu_ic_read(ipu, IC_CONF);
278
279         /* Setup color space conversion */
280         in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_pixel_fmt);
281         out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
282         if (in_fmt == RGB) {
283                 if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
284                         /* Enable RGB->YCBCR CSC1 */
285                         _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 1);
286                         ic_conf |= IC_CONF_PRPVF_CSC1;
287                 }
288         }
289         if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
290                 if (out_fmt == RGB) {
291                         /* Enable YCBCR->RGB CSC1 */
292                         _init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 1);
293                         ic_conf |= IC_CONF_PRPVF_CSC1;
294                 } else {
295                         /* TODO: Support YUV<->YCbCr conversion? */
296                 }
297         }
298
299         if (params->mem_prp_vf_mem.graphics_combine_en) {
300                 ic_conf |= IC_CONF_PRPVF_CMB;
301
302                 if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
303                         /* need transparent CSC1 conversion */
304                         _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, RGB, 1);
305                         ic_conf |= IC_CONF_PRPVF_CSC1;  /* Enable RGB->RGB CSC */
306                 }
307                 in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
308                 out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
309                 if (in_fmt == RGB) {
310                         if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
311                                 /* Enable RGB->YCBCR CSC2 */
312                                 _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 2);
313                                 ic_conf |= IC_CONF_PRPVF_CSC2;
314                         }
315                 }
316                 if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
317                         if (out_fmt == RGB) {
318                                 /* Enable YCBCR->RGB CSC2 */
319                                 _init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 2);
320                                 ic_conf |= IC_CONF_PRPVF_CSC2;
321                         } else {
322                                 /* TODO: Support YUV<->YCbCr conversion? */
323                         }
324                 }
325
326                 if (params->mem_prp_vf_mem.global_alpha_en) {
327                         ic_conf |= IC_CONF_IC_GLB_LOC_A;
328                         reg = ipu_ic_read(ipu, IC_CMBP_1);
329                         reg &= ~(0xff);
330                         reg |= params->mem_prp_vf_mem.alpha;
331                         ipu_ic_write(ipu, reg, IC_CMBP_1);
332                 } else
333                         ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
334
335                 if (params->mem_prp_vf_mem.key_color_en) {
336                         ic_conf |= IC_CONF_KEY_COLOR_EN;
337                         ipu_ic_write(ipu, params->mem_prp_vf_mem.key_color,
338                                         IC_CMBP_2);
339                 } else
340                         ic_conf &= ~IC_CONF_KEY_COLOR_EN;
341         } else {
342                 ic_conf &= ~IC_CONF_PRPVF_CMB;
343         }
344
345         if (src_is_csi)
346                 ic_conf &= ~IC_CONF_RWS_EN;
347         else
348                 ic_conf |= IC_CONF_RWS_EN;
349
350         ipu_ic_write(ipu, ic_conf, IC_CONF);
351
352         return ret;
353 }
354
355 void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu)
356 {
357         uint32_t reg;
358
359         reg = ipu_ic_read(ipu, IC_CONF);
360         reg &= ~(IC_CONF_PRPVF_EN | IC_CONF_PRPVF_CMB |
361                  IC_CONF_PRPVF_CSC2 | IC_CONF_PRPVF_CSC1);
362         ipu_ic_write(ipu, reg, IC_CONF);
363 }
364
365 void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params)
366 {
367 }
368
369 void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu)
370 {
371         uint32_t reg;
372         reg = ipu_ic_read(ipu, IC_CONF);
373         reg &= ~IC_CONF_PRPVF_ROT_EN;
374         ipu_ic_write(ipu, reg, IC_CONF);
375 }
376
377 int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
378                         bool src_is_csi)
379 {
380         uint32_t reg, ic_conf;
381         uint32_t downsizeCoeff, resizeCoeff;
382         ipu_color_space_t in_fmt, out_fmt;
383         int ret = 0;
384
385         /* Setup vertical resizing */
386         if (!params->mem_prp_enc_mem.outv_resize_ratio) {
387                 ret = _calc_resize_coeffs(ipu,
388                                         params->mem_prp_enc_mem.in_height,
389                                         params->mem_prp_enc_mem.out_height,
390                                         &resizeCoeff, &downsizeCoeff);
391                 if (ret < 0) {
392                         dev_err(ipu->dev, "failed to calculate prpenc height "
393                                 "scaling coefficients\n");
394                         return ret;
395                 }
396
397                 reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
398         } else
399                 reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
400
401         /* Setup horizontal resizing */
402         if (!params->mem_prp_enc_mem.outh_resize_ratio) {
403                 ret = _calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
404                                         params->mem_prp_enc_mem.out_width,
405                                         &resizeCoeff, &downsizeCoeff);
406                 if (ret < 0) {
407                         dev_err(ipu->dev, "failed to calculate prpenc width "
408                                 "scaling coefficients\n");
409                         return ret;
410                 }
411
412                 reg |= (downsizeCoeff << 14) | resizeCoeff;
413         } else
414                 reg |= params->mem_prp_enc_mem.outh_resize_ratio;
415
416         ipu_ic_write(ipu, reg, IC_PRP_ENC_RSC);
417
418         ic_conf = ipu_ic_read(ipu, IC_CONF);
419
420         /* Setup color space conversion */
421         in_fmt = format_to_colorspace(params->mem_prp_enc_mem.in_pixel_fmt);
422         out_fmt = format_to_colorspace(params->mem_prp_enc_mem.out_pixel_fmt);
423         if (in_fmt == RGB) {
424                 if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
425                         /* Enable RGB->YCBCR CSC1 */
426                         _init_csc(ipu, IC_TASK_ENCODER, RGB, out_fmt, 1);
427                         ic_conf |= IC_CONF_PRPENC_CSC1;
428                 }
429         }
430         if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
431                 if (out_fmt == RGB) {
432                         /* Enable YCBCR->RGB CSC1 */
433                         _init_csc(ipu, IC_TASK_ENCODER, YCbCr, RGB, 1);
434                         ic_conf |= IC_CONF_PRPENC_CSC1;
435                 } else {
436                         /* TODO: Support YUV<->YCbCr conversion? */
437                 }
438         }
439
440         if (src_is_csi)
441                 ic_conf &= ~IC_CONF_RWS_EN;
442         else
443                 ic_conf |= IC_CONF_RWS_EN;
444
445         ipu_ic_write(ipu, ic_conf, IC_CONF);
446
447         return ret;
448 }
449
450 void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu)
451 {
452         uint32_t reg;
453
454         reg = ipu_ic_read(ipu, IC_CONF);
455         reg &= ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1);
456         ipu_ic_write(ipu, reg, IC_CONF);
457 }
458
459 void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params)
460 {
461 }
462
463 void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu)
464 {
465         uint32_t reg;
466
467         reg = ipu_ic_read(ipu, IC_CONF);
468         reg &= ~(IC_CONF_PRPENC_ROT_EN);
469         ipu_ic_write(ipu, reg, IC_CONF);
470 }
471
472 int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
473 {
474         uint32_t reg, ic_conf;
475         uint32_t downsizeCoeff, resizeCoeff;
476         ipu_color_space_t in_fmt, out_fmt;
477         int ret = 0;
478
479         /* Setup vertical resizing */
480         if (!params->mem_pp_mem.outv_resize_ratio) {
481                 ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
482                                     params->mem_pp_mem.out_height,
483                                     &resizeCoeff, &downsizeCoeff);
484                 if (ret < 0) {
485                         dev_err(ipu->dev, "failed to calculate pp height "
486                                 "scaling coefficients\n");
487                         return ret;
488                 }
489
490                 reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
491         } else {
492                 reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
493         }
494
495         /* Setup horizontal resizing */
496         if (!params->mem_pp_mem.outh_resize_ratio) {
497                 ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
498                                         params->mem_pp_mem.out_width,
499                                         &resizeCoeff, &downsizeCoeff);
500                 if (ret < 0) {
501                         dev_err(ipu->dev, "failed to calculate pp width "
502                                 "scaling coefficients\n");
503                         return ret;
504                 }
505
506                 reg |= (downsizeCoeff << 14) | resizeCoeff;
507         } else {
508                 reg |= params->mem_pp_mem.outh_resize_ratio;
509         }
510
511         ipu_ic_write(ipu, reg, IC_PP_RSC);
512
513         ic_conf = ipu_ic_read(ipu, IC_CONF);
514
515         /* Setup color space conversion */
516         in_fmt = format_to_colorspace(params->mem_pp_mem.in_pixel_fmt);
517         out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
518         if (in_fmt == RGB) {
519                 if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
520                         /* Enable RGB->YCBCR CSC1 */
521                         _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 1);
522                         ic_conf |= IC_CONF_PP_CSC1;
523                 }
524         }
525         if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
526                 if (out_fmt == RGB) {
527                         /* Enable YCBCR->RGB CSC1 */
528                         _init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 1);
529                         ic_conf |= IC_CONF_PP_CSC1;
530                 } else {
531                         /* TODO: Support YUV<->YCbCr conversion? */
532                 }
533         }
534
535         if (params->mem_pp_mem.graphics_combine_en) {
536                 ic_conf |= IC_CONF_PP_CMB;
537
538                 if (!(ic_conf & IC_CONF_PP_CSC1)) {
539                         /* need transparent CSC1 conversion */
540                         _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
541                         ic_conf |= IC_CONF_PP_CSC1;  /* Enable RGB->RGB CSC */
542                 }
543
544                 in_fmt = format_to_colorspace(params->mem_pp_mem.in_g_pixel_fmt);
545                 out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
546                 if (in_fmt == RGB) {
547                         if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
548                                 /* Enable RGB->YCBCR CSC2 */
549                                 _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 2);
550                                 ic_conf |= IC_CONF_PP_CSC2;
551                         }
552                 }
553                 if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
554                         if (out_fmt == RGB) {
555                                 /* Enable YCBCR->RGB CSC2 */
556                                 _init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 2);
557                                 ic_conf |= IC_CONF_PP_CSC2;
558                         } else {
559                                 /* TODO: Support YUV<->YCbCr conversion? */
560                         }
561                 }
562
563                 if (params->mem_pp_mem.global_alpha_en) {
564                         ic_conf |= IC_CONF_IC_GLB_LOC_A;
565                         reg = ipu_ic_read(ipu, IC_CMBP_1);
566                         reg &= ~(0xff00);
567                         reg |= (params->mem_pp_mem.alpha << 8);
568                         ipu_ic_write(ipu, reg, IC_CMBP_1);
569                 } else
570                         ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
571
572                 if (params->mem_pp_mem.key_color_en) {
573                         ic_conf |= IC_CONF_KEY_COLOR_EN;
574                         ipu_ic_write(ipu, params->mem_pp_mem.key_color,
575                                         IC_CMBP_2);
576                 } else
577                         ic_conf &= ~IC_CONF_KEY_COLOR_EN;
578         } else {
579                 ic_conf &= ~IC_CONF_PP_CMB;
580         }
581
582         ipu_ic_write(ipu, ic_conf, IC_CONF);
583
584         return ret;
585 }
586
587 void _ipu_ic_uninit_pp(struct ipu_soc *ipu)
588 {
589         uint32_t reg;
590
591         reg = ipu_ic_read(ipu, IC_CONF);
592         reg &= ~(IC_CONF_PP_EN | IC_CONF_PP_CSC1 | IC_CONF_PP_CSC2 |
593                  IC_CONF_PP_CMB);
594         ipu_ic_write(ipu, reg, IC_CONF);
595 }
596
597 void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
598 {
599 }
600
601 void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu)
602 {
603         uint32_t reg;
604         reg = ipu_ic_read(ipu, IC_CONF);
605         reg &= ~IC_CONF_PP_ROT_EN;
606         ipu_ic_write(ipu, reg, IC_CONF);
607 }
608
609 int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
610                 uint16_t width, uint16_t height,
611                 int burst_size, ipu_rotate_mode_t rot)
612 {
613         u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
614         u32 temp_rot = bitrev8(rot) >> 5;
615         bool need_hor_flip = false;
616
617         if ((burst_size != 8) && (burst_size != 16)) {
618                 dev_dbg(ipu->dev, "Illegal burst length for IC\n");
619                 return -EINVAL;
620         }
621
622         width--;
623         height--;
624
625         if (temp_rot & 0x2)     /* Need horizontal flip */
626                 need_hor_flip = true;
627
628         ic_idmac_1 = ipu_ic_read(ipu, IC_IDMAC_1);
629         ic_idmac_2 = ipu_ic_read(ipu, IC_IDMAC_2);
630         ic_idmac_3 = ipu_ic_read(ipu, IC_IDMAC_3);
631         if (dma_chan == 22) {   /* PP output - CB2 */
632                 if (burst_size == 16)
633                         ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
634                 else
635                         ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
636
637                 if (need_hor_flip)
638                         ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
639                 else
640                         ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
641
642                 ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
643                 ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
644
645                 ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
646                 ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
647         } else if (dma_chan == 11) {    /* PP Input - CB5 */
648                 if (burst_size == 16)
649                         ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
650                 else
651                         ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
652         } else if (dma_chan == 47) {    /* PP Rot input */
653                 ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
654                 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
655         }
656
657         if (dma_chan == 12) {   /* PRP Input - CB6 */
658                 if (burst_size == 16)
659                         ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
660                 else
661                         ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
662         }
663
664         if (dma_chan == 20) {   /* PRP ENC output - CB0 */
665                 if (burst_size == 16)
666                         ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
667                 else
668                         ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
669
670                 if (need_hor_flip)
671                         ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
672                 else
673                         ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
674
675                 ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
676                 ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
677
678                 ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
679                 ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
680
681         } else if (dma_chan == 45) {    /* PRP ENC Rot input */
682                 ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
683                 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
684         }
685
686         if (dma_chan == 21) {   /* PRP VF output - CB1 */
687                 if (burst_size == 16)
688                         ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
689                 else
690                         ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
691
692                 if (need_hor_flip)
693                         ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
694                 else
695                         ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
696
697                 ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
698                 ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
699
700                 ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
701                 ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
702
703         } else if (dma_chan == 46) {    /* PRP VF Rot input */
704                 ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
705                 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
706         }
707
708         if (dma_chan == 14) {   /* PRP VF graphics combining input - CB3 */
709                 if (burst_size == 16)
710                         ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
711                 else
712                         ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
713         } else if (dma_chan == 15) {    /* PP graphics combining input - CB4 */
714                 if (burst_size == 16)
715                         ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
716                 else
717                         ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
718         } else if (dma_chan == 5) {     /* VDIC OUTPUT - CB7 */
719                 if (burst_size == 16)
720                         ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
721                 else
722                         ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
723         }
724
725         ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
726         ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
727         ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
728         return 0;
729 }
730
731 static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
732                       ipu_color_space_t out_format, int csc_index)
733 {
734         /*
735          * Y =  0.257 * R + 0.504 * G + 0.098 * B +  16;
736          * U = -0.148 * R - 0.291 * G + 0.439 * B + 128;
737          * V =  0.439 * R - 0.368 * G - 0.071 * B + 128;
738          */
739         static const uint32_t rgb2ycbcr_coeff[4][3] = {
740                 {0x0042, 0x0081, 0x0019},
741                 {0x01DA, 0x01B6, 0x0070},
742                 {0x0070, 0x01A2, 0x01EE},
743                 {0x0040, 0x0200, 0x0200},       /* A0, A1, A2 */
744         };
745
746         /* transparent RGB->RGB matrix for combining
747          */
748         static const uint32_t rgb2rgb_coeff[4][3] = {
749                 {0x0080, 0x0000, 0x0000},
750                 {0x0000, 0x0080, 0x0000},
751                 {0x0000, 0x0000, 0x0080},
752                 {0x0000, 0x0000, 0x0000},       /* A0, A1, A2 */
753         };
754
755 /*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
756        G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
757        B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
758         static const uint32_t ycbcr2rgb_coeff[4][3] = {
759                 {149, 0, 204},
760                 {149, 462, 408},
761                 {149, 255, 0},
762                 {8192 - 446, 266, 8192 - 554},  /* A0, A1, A2 */
763         };
764
765         uint32_t param;
766         uint32_t *base = NULL;
767
768         if (ic_task == IC_TASK_ENCODER) {
769                 base = ipu->tpmem_base + 0x2008 / 4;
770         } else if (ic_task == IC_TASK_VIEWFINDER) {
771                 if (csc_index == 1)
772                         base = ipu->tpmem_base + 0x4028 / 4;
773                 else
774                         base = ipu->tpmem_base + 0x4040 / 4;
775         } else if (ic_task == IC_TASK_POST_PROCESSOR) {
776                 if (csc_index == 1)
777                         base = ipu->tpmem_base + 0x6060 / 4;
778                 else
779                         base = ipu->tpmem_base + 0x6078 / 4;
780         } else {
781                 BUG();
782         }
783
784         if ((in_format == YCbCr) && (out_format == RGB)) {
785                 /* Init CSC (YCbCr->RGB) */
786                 param = (ycbcr2rgb_coeff[3][0] << 27) |
787                         (ycbcr2rgb_coeff[0][0] << 18) |
788                         (ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
789                 writel(param, base++);
790                 /* scale = 2, sat = 0 */
791                 param = (ycbcr2rgb_coeff[3][0] >> 5) | (2L << (40 - 32));
792                 writel(param, base++);
793
794                 param = (ycbcr2rgb_coeff[3][1] << 27) |
795                         (ycbcr2rgb_coeff[0][1] << 18) |
796                         (ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
797                 writel(param, base++);
798                 param = (ycbcr2rgb_coeff[3][1] >> 5);
799                 writel(param, base++);
800
801                 param = (ycbcr2rgb_coeff[3][2] << 27) |
802                         (ycbcr2rgb_coeff[0][2] << 18) |
803                         (ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
804                 writel(param, base++);
805                 param = (ycbcr2rgb_coeff[3][2] >> 5);
806                 writel(param, base++);
807         } else if ((in_format == RGB) && (out_format == YCbCr)) {
808                 /* Init CSC (RGB->YCbCr) */
809                 param = (rgb2ycbcr_coeff[3][0] << 27) |
810                         (rgb2ycbcr_coeff[0][0] << 18) |
811                         (rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
812                 writel(param, base++);
813                 /* scale = 1, sat = 0 */
814                 param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
815                 writel(param, base++);
816
817                 param = (rgb2ycbcr_coeff[3][1] << 27) |
818                         (rgb2ycbcr_coeff[0][1] << 18) |
819                         (rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
820                 writel(param, base++);
821                 param = (rgb2ycbcr_coeff[3][1] >> 5);
822                 writel(param, base++);
823
824                 param = (rgb2ycbcr_coeff[3][2] << 27) |
825                         (rgb2ycbcr_coeff[0][2] << 18) |
826                         (rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
827                 writel(param, base++);
828                 param = (rgb2ycbcr_coeff[3][2] >> 5);
829                 writel(param, base++);
830         } else if ((in_format == RGB) && (out_format == RGB)) {
831                 /* Init CSC */
832                 param =
833                     (rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
834                     (rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
835                 writel(param, base++);
836                 /* scale = 2, sat = 0 */
837                 param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
838                 writel(param, base++);
839
840                 param =
841                     (rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
842                     (rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
843                 writel(param, base++);
844                 param = (rgb2rgb_coeff[3][1] >> 5);
845                 writel(param, base++);
846
847                 param =
848                     (rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
849                     (rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
850                 writel(param, base++);
851                 param = (rgb2rgb_coeff[3][2] >> 5);
852                 writel(param, base++);
853         } else {
854                 dev_err(ipu->dev, "Unsupported color space conversion\n");
855         }
856 }
857
858 static int _calc_resize_coeffs(struct ipu_soc *ipu,
859                                 uint32_t inSize, uint32_t outSize,
860                                 uint32_t *resizeCoeff,
861                                 uint32_t *downsizeCoeff)
862 {
863         uint32_t tempSize;
864         uint32_t tempDownsize;
865
866         if (inSize > 4096) {
867                 dev_err(ipu->dev, "IC input size(%d) cannot exceed 4096\n",
868                         inSize);
869                 return -EINVAL;
870         }
871
872         if (outSize > 1024) {
873                 dev_err(ipu->dev, "IC output size(%d) cannot exceed 1024\n",
874                         outSize);
875                 return -EINVAL;
876         }
877
878         if ((outSize << 3) < inSize) {
879                 dev_err(ipu->dev, "IC cannot downsize more than 8:1\n");
880                 return -EINVAL;
881         }
882
883         /* Compute downsizing coefficient */
884         /* Output of downsizing unit cannot be more than 1024 */
885         tempDownsize = 0;
886         tempSize = inSize;
887         while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
888                (tempDownsize < 2)) {
889                 tempSize >>= 1;
890                 tempDownsize++;
891         }
892         *downsizeCoeff = tempDownsize;
893
894         /* compute resizing coefficient using the following equation:
895            resizeCoeff = M*(SI -1)/(SO - 1)
896            where M = 2^13, SI - input size, SO - output size    */
897         *resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
898         if (*resizeCoeff >= 16384L) {
899                 dev_err(ipu->dev, "Overflow on IC resize coefficient.\n");
900                 return -EINVAL;
901         }
902
903         dev_dbg(ipu->dev, "resizing from %u -> %u pixels, "
904                 "downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
905                 *downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
906                 ((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
907
908         return 0;
909 }
910
911 void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu)
912 {
913         uint32_t reg;
914         uint32_t mask_reg;
915
916         reg = ipu_vdi_read(ipu, VDI_C);
917         mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
918         if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
919                 reg &= ~VDI_C_TOP_FIELD_MAN_1;
920         else
921                 reg |= VDI_C_TOP_FIELD_MAN_1;
922
923         ipu_vdi_write(ipu, reg, VDI_C);
924 }