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