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