]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/ipu3/ipu_ic.c
ENGR00280663-1 IPUv3: improve IC scale check logic
[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                 (params->mem_prp_vf_mem.outv_resize_ratio >=
248                                                 IC_RSZ_MAX_RESIZE_RATIO)) {
249                 ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
250                                         params->mem_prp_vf_mem.out_height,
251                                         &resizeCoeff, &downsizeCoeff);
252                 if (ret < 0) {
253                         dev_err(ipu->dev, "failed to calculate prpvf height "
254                                 "scaling coefficients\n");
255                         return ret;
256                 }
257
258                 reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
259         } else
260                 reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
261
262         /* Setup horizontal resizing */
263         /* Upadeted for IC split case */
264         if (!(params->mem_prp_vf_mem.outh_resize_ratio) ||
265                 (params->mem_prp_vf_mem.outh_resize_ratio >=
266                                                 IC_RSZ_MAX_RESIZE_RATIO)) {
267                 ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
268                                         params->mem_prp_vf_mem.out_width,
269                                         &resizeCoeff, &downsizeCoeff);
270                 if (ret < 0) {
271                         dev_err(ipu->dev, "failed to calculate prpvf width "
272                                 "scaling coefficients\n");
273                         return ret;
274                 }
275
276                 reg |= (downsizeCoeff << 14) | resizeCoeff;
277         } else
278                 reg |= params->mem_prp_vf_mem.outh_resize_ratio;
279
280         ipu_ic_write(ipu, reg, IC_PRP_VF_RSC);
281
282         ic_conf = ipu_ic_read(ipu, IC_CONF);
283
284         /* Setup color space conversion */
285         in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_pixel_fmt);
286         out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
287         if (in_fmt == RGB) {
288                 if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
289                         /* Enable RGB->YCBCR CSC1 */
290                         _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 1);
291                         ic_conf |= IC_CONF_PRPVF_CSC1;
292                 }
293         }
294         if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
295                 if (out_fmt == RGB) {
296                         /* Enable YCBCR->RGB CSC1 */
297                         _init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 1);
298                         ic_conf |= IC_CONF_PRPVF_CSC1;
299                 } else {
300                         /* TODO: Support YUV<->YCbCr conversion? */
301                 }
302         }
303
304         if (params->mem_prp_vf_mem.graphics_combine_en) {
305                 ic_conf |= IC_CONF_PRPVF_CMB;
306
307                 if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
308                         /* need transparent CSC1 conversion */
309                         _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, RGB, 1);
310                         ic_conf |= IC_CONF_PRPVF_CSC1;  /* Enable RGB->RGB CSC */
311                 }
312                 in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
313                 out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
314                 if (in_fmt == RGB) {
315                         if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
316                                 /* Enable RGB->YCBCR CSC2 */
317                                 _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 2);
318                                 ic_conf |= IC_CONF_PRPVF_CSC2;
319                         }
320                 }
321                 if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
322                         if (out_fmt == RGB) {
323                                 /* Enable YCBCR->RGB CSC2 */
324                                 _init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 2);
325                                 ic_conf |= IC_CONF_PRPVF_CSC2;
326                         } else {
327                                 /* TODO: Support YUV<->YCbCr conversion? */
328                         }
329                 }
330
331                 if (params->mem_prp_vf_mem.global_alpha_en) {
332                         ic_conf |= IC_CONF_IC_GLB_LOC_A;
333                         reg = ipu_ic_read(ipu, IC_CMBP_1);
334                         reg &= ~(0xff);
335                         reg |= params->mem_prp_vf_mem.alpha;
336                         ipu_ic_write(ipu, reg, IC_CMBP_1);
337                 } else
338                         ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
339
340                 if (params->mem_prp_vf_mem.key_color_en) {
341                         ic_conf |= IC_CONF_KEY_COLOR_EN;
342                         ipu_ic_write(ipu, params->mem_prp_vf_mem.key_color,
343                                         IC_CMBP_2);
344                 } else
345                         ic_conf &= ~IC_CONF_KEY_COLOR_EN;
346         } else {
347                 ic_conf &= ~IC_CONF_PRPVF_CMB;
348         }
349
350         if (src_is_csi)
351                 ic_conf &= ~IC_CONF_RWS_EN;
352         else
353                 ic_conf |= IC_CONF_RWS_EN;
354
355         ipu_ic_write(ipu, ic_conf, IC_CONF);
356
357         return ret;
358 }
359
360 void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu)
361 {
362         uint32_t reg;
363
364         reg = ipu_ic_read(ipu, IC_CONF);
365         reg &= ~(IC_CONF_PRPVF_EN | IC_CONF_PRPVF_CMB |
366                  IC_CONF_PRPVF_CSC2 | IC_CONF_PRPVF_CSC1);
367         ipu_ic_write(ipu, reg, IC_CONF);
368 }
369
370 void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params)
371 {
372 }
373
374 void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu)
375 {
376         uint32_t reg;
377         reg = ipu_ic_read(ipu, IC_CONF);
378         reg &= ~IC_CONF_PRPVF_ROT_EN;
379         ipu_ic_write(ipu, reg, IC_CONF);
380 }
381
382 int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
383                         bool src_is_csi)
384 {
385         uint32_t reg, ic_conf;
386         uint32_t downsizeCoeff, resizeCoeff;
387         ipu_color_space_t in_fmt, out_fmt;
388         int ret = 0;
389
390         /* Setup vertical resizing */
391         if (!(params->mem_prp_enc_mem.outv_resize_ratio) ||
392                 (params->mem_prp_enc_mem.outv_resize_ratio >=
393                                                 IC_RSZ_MAX_RESIZE_RATIO)) {
394                 ret = _calc_resize_coeffs(ipu,
395                                         params->mem_prp_enc_mem.in_height,
396                                         params->mem_prp_enc_mem.out_height,
397                                         &resizeCoeff, &downsizeCoeff);
398                 if (ret < 0) {
399                         dev_err(ipu->dev, "failed to calculate prpenc height "
400                                 "scaling coefficients\n");
401                         return ret;
402                 }
403
404                 reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
405         } else
406                 reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
407
408         /* Setup horizontal resizing */
409         /* Upadeted for IC split case */
410         if (!(params->mem_prp_enc_mem.outh_resize_ratio) ||
411                 (params->mem_prp_enc_mem.outh_resize_ratio >=
412                                                 IC_RSZ_MAX_RESIZE_RATIO)) {
413                 ret = _calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
414                                         params->mem_prp_enc_mem.out_width,
415                                         &resizeCoeff, &downsizeCoeff);
416                 if (ret < 0) {
417                         dev_err(ipu->dev, "failed to calculate prpenc width "
418                                 "scaling coefficients\n");
419                         return ret;
420                 }
421
422                 reg |= (downsizeCoeff << 14) | resizeCoeff;
423         } else
424                 reg |= params->mem_prp_enc_mem.outh_resize_ratio;
425
426         ipu_ic_write(ipu, reg, IC_PRP_ENC_RSC);
427
428         ic_conf = ipu_ic_read(ipu, IC_CONF);
429
430         /* Setup color space conversion */
431         in_fmt = format_to_colorspace(params->mem_prp_enc_mem.in_pixel_fmt);
432         out_fmt = format_to_colorspace(params->mem_prp_enc_mem.out_pixel_fmt);
433         if (in_fmt == RGB) {
434                 if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
435                         /* Enable RGB->YCBCR CSC1 */
436                         _init_csc(ipu, IC_TASK_ENCODER, RGB, out_fmt, 1);
437                         ic_conf |= IC_CONF_PRPENC_CSC1;
438                 }
439         }
440         if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
441                 if (out_fmt == RGB) {
442                         /* Enable YCBCR->RGB CSC1 */
443                         _init_csc(ipu, IC_TASK_ENCODER, YCbCr, RGB, 1);
444                         ic_conf |= IC_CONF_PRPENC_CSC1;
445                 } else {
446                         /* TODO: Support YUV<->YCbCr conversion? */
447                 }
448         }
449
450         if (src_is_csi)
451                 ic_conf &= ~IC_CONF_RWS_EN;
452         else
453                 ic_conf |= IC_CONF_RWS_EN;
454
455         ipu_ic_write(ipu, ic_conf, IC_CONF);
456
457         return ret;
458 }
459
460 void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu)
461 {
462         uint32_t reg;
463
464         reg = ipu_ic_read(ipu, IC_CONF);
465         reg &= ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1);
466         ipu_ic_write(ipu, reg, IC_CONF);
467 }
468
469 void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params)
470 {
471 }
472
473 void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu)
474 {
475         uint32_t reg;
476
477         reg = ipu_ic_read(ipu, IC_CONF);
478         reg &= ~(IC_CONF_PRPENC_ROT_EN);
479         ipu_ic_write(ipu, reg, IC_CONF);
480 }
481
482 int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
483 {
484         uint32_t reg, ic_conf;
485         uint32_t downsizeCoeff, resizeCoeff;
486         ipu_color_space_t in_fmt, out_fmt;
487         int ret = 0;
488
489         /* Setup vertical resizing */
490         if (!(params->mem_pp_mem.outv_resize_ratio) ||
491                 (params->mem_pp_mem.outv_resize_ratio >=
492                                                 IC_RSZ_MAX_RESIZE_RATIO)) {
493                 ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
494                                     params->mem_pp_mem.out_height,
495                                     &resizeCoeff, &downsizeCoeff);
496                 if (ret < 0) {
497                         dev_err(ipu->dev, "failed to calculate pp height "
498                                 "scaling coefficients\n");
499                         return ret;
500                 }
501
502                 reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
503         } else {
504                 reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
505         }
506
507         /* Setup horizontal resizing */
508         /* Upadeted for IC split case */
509         if (!(params->mem_pp_mem.outh_resize_ratio) ||
510                 (params->mem_pp_mem.outh_resize_ratio >=
511                                                 IC_RSZ_MAX_RESIZE_RATIO)) {
512                 ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
513                                         params->mem_pp_mem.out_width,
514                                         &resizeCoeff, &downsizeCoeff);
515                 if (ret < 0) {
516                         dev_err(ipu->dev, "failed to calculate pp width "
517                                 "scaling coefficients\n");
518                         return ret;
519                 }
520
521                 reg |= (downsizeCoeff << 14) | resizeCoeff;
522         } else {
523                 reg |= params->mem_pp_mem.outh_resize_ratio;
524         }
525
526         ipu_ic_write(ipu, reg, IC_PP_RSC);
527
528         ic_conf = ipu_ic_read(ipu, IC_CONF);
529
530         /* Setup color space conversion */
531         in_fmt = format_to_colorspace(params->mem_pp_mem.in_pixel_fmt);
532         out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
533         if (in_fmt == RGB) {
534                 if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
535                         /* Enable RGB->YCBCR CSC1 */
536                         _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 1);
537                         ic_conf |= IC_CONF_PP_CSC1;
538                 }
539         }
540         if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
541                 if (out_fmt == RGB) {
542                         /* Enable YCBCR->RGB CSC1 */
543                         _init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 1);
544                         ic_conf |= IC_CONF_PP_CSC1;
545                 } else {
546                         /* TODO: Support YUV<->YCbCr conversion? */
547                 }
548         }
549
550         if (params->mem_pp_mem.graphics_combine_en) {
551                 ic_conf |= IC_CONF_PP_CMB;
552
553                 if (!(ic_conf & IC_CONF_PP_CSC1)) {
554                         /* need transparent CSC1 conversion */
555                         _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
556                         ic_conf |= IC_CONF_PP_CSC1;  /* Enable RGB->RGB CSC */
557                 }
558
559                 in_fmt = format_to_colorspace(params->mem_pp_mem.in_g_pixel_fmt);
560                 out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
561                 if (in_fmt == RGB) {
562                         if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
563                                 /* Enable RGB->YCBCR CSC2 */
564                                 _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 2);
565                                 ic_conf |= IC_CONF_PP_CSC2;
566                         }
567                 }
568                 if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
569                         if (out_fmt == RGB) {
570                                 /* Enable YCBCR->RGB CSC2 */
571                                 _init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 2);
572                                 ic_conf |= IC_CONF_PP_CSC2;
573                         } else {
574                                 /* TODO: Support YUV<->YCbCr conversion? */
575                         }
576                 }
577
578                 if (params->mem_pp_mem.global_alpha_en) {
579                         ic_conf |= IC_CONF_IC_GLB_LOC_A;
580                         reg = ipu_ic_read(ipu, IC_CMBP_1);
581                         reg &= ~(0xff00);
582                         reg |= (params->mem_pp_mem.alpha << 8);
583                         ipu_ic_write(ipu, reg, IC_CMBP_1);
584                 } else
585                         ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
586
587                 if (params->mem_pp_mem.key_color_en) {
588                         ic_conf |= IC_CONF_KEY_COLOR_EN;
589                         ipu_ic_write(ipu, params->mem_pp_mem.key_color,
590                                         IC_CMBP_2);
591                 } else
592                         ic_conf &= ~IC_CONF_KEY_COLOR_EN;
593         } else {
594                 ic_conf &= ~IC_CONF_PP_CMB;
595         }
596
597         ipu_ic_write(ipu, ic_conf, IC_CONF);
598
599         return ret;
600 }
601
602 void _ipu_ic_uninit_pp(struct ipu_soc *ipu)
603 {
604         uint32_t reg;
605
606         reg = ipu_ic_read(ipu, IC_CONF);
607         reg &= ~(IC_CONF_PP_EN | IC_CONF_PP_CSC1 | IC_CONF_PP_CSC2 |
608                  IC_CONF_PP_CMB);
609         ipu_ic_write(ipu, reg, IC_CONF);
610 }
611
612 void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
613 {
614 }
615
616 void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu)
617 {
618         uint32_t reg;
619         reg = ipu_ic_read(ipu, IC_CONF);
620         reg &= ~IC_CONF_PP_ROT_EN;
621         ipu_ic_write(ipu, reg, IC_CONF);
622 }
623
624 int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
625                 uint16_t width, uint16_t height,
626                 int burst_size, ipu_rotate_mode_t rot)
627 {
628         u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
629         u32 temp_rot = bitrev8(rot) >> 5;
630         bool need_hor_flip = false;
631
632         if ((burst_size != 8) && (burst_size != 16)) {
633                 dev_dbg(ipu->dev, "Illegal burst length for IC\n");
634                 return -EINVAL;
635         }
636
637         width--;
638         height--;
639
640         if (temp_rot & 0x2)     /* Need horizontal flip */
641                 need_hor_flip = true;
642
643         ic_idmac_1 = ipu_ic_read(ipu, IC_IDMAC_1);
644         ic_idmac_2 = ipu_ic_read(ipu, IC_IDMAC_2);
645         ic_idmac_3 = ipu_ic_read(ipu, IC_IDMAC_3);
646         if (dma_chan == 22) {   /* PP output - CB2 */
647                 if (burst_size == 16)
648                         ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
649                 else
650                         ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
651
652                 if (need_hor_flip)
653                         ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
654                 else
655                         ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
656
657                 ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
658                 ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
659
660                 ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
661                 ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
662         } else if (dma_chan == 11) {    /* PP Input - CB5 */
663                 if (burst_size == 16)
664                         ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
665                 else
666                         ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
667         } else if (dma_chan == 47) {    /* PP Rot input */
668                 ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
669                 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
670         }
671
672         if (dma_chan == 12) {   /* PRP Input - CB6 */
673                 if (burst_size == 16)
674                         ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
675                 else
676                         ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
677         }
678
679         if (dma_chan == 20) {   /* PRP ENC output - CB0 */
680                 if (burst_size == 16)
681                         ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
682                 else
683                         ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
684
685                 if (need_hor_flip)
686                         ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
687                 else
688                         ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
689
690                 ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
691                 ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
692
693                 ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
694                 ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
695
696         } else if (dma_chan == 45) {    /* PRP ENC Rot input */
697                 ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
698                 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
699         }
700
701         if (dma_chan == 21) {   /* PRP VF output - CB1 */
702                 if (burst_size == 16)
703                         ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
704                 else
705                         ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
706
707                 if (need_hor_flip)
708                         ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
709                 else
710                         ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
711
712                 ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
713                 ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
714
715                 ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
716                 ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
717
718         } else if (dma_chan == 46) {    /* PRP VF Rot input */
719                 ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
720                 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
721         }
722
723         if (dma_chan == 14) {   /* PRP VF graphics combining input - CB3 */
724                 if (burst_size == 16)
725                         ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
726                 else
727                         ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
728         } else if (dma_chan == 15) {    /* PP graphics combining input - CB4 */
729                 if (burst_size == 16)
730                         ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
731                 else
732                         ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
733         } else if (dma_chan == 5) {     /* VDIC OUTPUT - CB7 */
734                 if (burst_size == 16)
735                         ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
736                 else
737                         ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
738         }
739
740         ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
741         ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
742         ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
743         return 0;
744 }
745
746 static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
747                       ipu_color_space_t out_format, int csc_index)
748 {
749         /*
750          * Y =  0.257 * R + 0.504 * G + 0.098 * B +  16;
751          * U = -0.148 * R - 0.291 * G + 0.439 * B + 128;
752          * V =  0.439 * R - 0.368 * G - 0.071 * B + 128;
753          */
754         static const uint32_t rgb2ycbcr_coeff[4][3] = {
755                 {0x0042, 0x0081, 0x0019},
756                 {0x01DA, 0x01B6, 0x0070},
757                 {0x0070, 0x01A2, 0x01EE},
758                 {0x0040, 0x0200, 0x0200},       /* A0, A1, A2 */
759         };
760
761         /* transparent RGB->RGB matrix for combining
762          */
763         static const uint32_t rgb2rgb_coeff[4][3] = {
764                 {0x0080, 0x0000, 0x0000},
765                 {0x0000, 0x0080, 0x0000},
766                 {0x0000, 0x0000, 0x0080},
767                 {0x0000, 0x0000, 0x0000},       /* A0, A1, A2 */
768         };
769
770 /*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
771        G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
772        B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
773         static const uint32_t ycbcr2rgb_coeff[4][3] = {
774                 {149, 0, 204},
775                 {149, 462, 408},
776                 {149, 255, 0},
777                 {8192 - 446, 266, 8192 - 554},  /* A0, A1, A2 */
778         };
779
780         uint32_t param;
781         uint32_t *base = NULL;
782
783         if (ic_task == IC_TASK_ENCODER) {
784                 base = ipu->tpmem_base + 0x2008 / 4;
785         } else if (ic_task == IC_TASK_VIEWFINDER) {
786                 if (csc_index == 1)
787                         base = ipu->tpmem_base + 0x4028 / 4;
788                 else
789                         base = ipu->tpmem_base + 0x4040 / 4;
790         } else if (ic_task == IC_TASK_POST_PROCESSOR) {
791                 if (csc_index == 1)
792                         base = ipu->tpmem_base + 0x6060 / 4;
793                 else
794                         base = ipu->tpmem_base + 0x6078 / 4;
795         } else {
796                 BUG();
797         }
798
799         if ((in_format == YCbCr) && (out_format == RGB)) {
800                 /* Init CSC (YCbCr->RGB) */
801                 param = (ycbcr2rgb_coeff[3][0] << 27) |
802                         (ycbcr2rgb_coeff[0][0] << 18) |
803                         (ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
804                 writel(param, base++);
805                 /* scale = 2, sat = 0 */
806                 param = (ycbcr2rgb_coeff[3][0] >> 5) | (2L << (40 - 32));
807                 writel(param, base++);
808
809                 param = (ycbcr2rgb_coeff[3][1] << 27) |
810                         (ycbcr2rgb_coeff[0][1] << 18) |
811                         (ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
812                 writel(param, base++);
813                 param = (ycbcr2rgb_coeff[3][1] >> 5);
814                 writel(param, base++);
815
816                 param = (ycbcr2rgb_coeff[3][2] << 27) |
817                         (ycbcr2rgb_coeff[0][2] << 18) |
818                         (ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
819                 writel(param, base++);
820                 param = (ycbcr2rgb_coeff[3][2] >> 5);
821                 writel(param, base++);
822         } else if ((in_format == RGB) && (out_format == YCbCr)) {
823                 /* Init CSC (RGB->YCbCr) */
824                 param = (rgb2ycbcr_coeff[3][0] << 27) |
825                         (rgb2ycbcr_coeff[0][0] << 18) |
826                         (rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
827                 writel(param, base++);
828                 /* scale = 1, sat = 0 */
829                 param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
830                 writel(param, base++);
831
832                 param = (rgb2ycbcr_coeff[3][1] << 27) |
833                         (rgb2ycbcr_coeff[0][1] << 18) |
834                         (rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
835                 writel(param, base++);
836                 param = (rgb2ycbcr_coeff[3][1] >> 5);
837                 writel(param, base++);
838
839                 param = (rgb2ycbcr_coeff[3][2] << 27) |
840                         (rgb2ycbcr_coeff[0][2] << 18) |
841                         (rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
842                 writel(param, base++);
843                 param = (rgb2ycbcr_coeff[3][2] >> 5);
844                 writel(param, base++);
845         } else if ((in_format == RGB) && (out_format == RGB)) {
846                 /* Init CSC */
847                 param =
848                     (rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
849                     (rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
850                 writel(param, base++);
851                 /* scale = 2, sat = 0 */
852                 param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
853                 writel(param, base++);
854
855                 param =
856                     (rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
857                     (rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
858                 writel(param, base++);
859                 param = (rgb2rgb_coeff[3][1] >> 5);
860                 writel(param, base++);
861
862                 param =
863                     (rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
864                     (rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
865                 writel(param, base++);
866                 param = (rgb2rgb_coeff[3][2] >> 5);
867                 writel(param, base++);
868         } else {
869                 dev_err(ipu->dev, "Unsupported color space conversion\n");
870         }
871 }
872
873 static int _calc_resize_coeffs(struct ipu_soc *ipu,
874                                 uint32_t inSize, uint32_t outSize,
875                                 uint32_t *resizeCoeff,
876                                 uint32_t *downsizeCoeff)
877 {
878         uint32_t tempSize;
879         uint32_t tempDownsize;
880
881         if (inSize > 4096) {
882                 dev_err(ipu->dev, "IC input size(%d) cannot exceed 4096\n",
883                         inSize);
884                 return -EINVAL;
885         }
886
887         if (outSize > 1024) {
888                 dev_err(ipu->dev, "IC output size(%d) cannot exceed 1024\n",
889                         outSize);
890                 return -EINVAL;
891         }
892
893         if ((outSize << 3) < inSize) {
894                 dev_err(ipu->dev, "IC cannot downsize more than 8:1\n");
895                 return -EINVAL;
896         }
897
898         /* Compute downsizing coefficient */
899         /* Output of downsizing unit cannot be more than 1024 */
900         tempDownsize = 0;
901         tempSize = inSize;
902         while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
903                (tempDownsize < 2)) {
904                 tempSize >>= 1;
905                 tempDownsize++;
906         }
907         *downsizeCoeff = tempDownsize;
908
909         /* compute resizing coefficient using the following equation:
910            resizeCoeff = M*(SI -1)/(SO - 1)
911            where M = 2^13, SI - input size, SO - output size    */
912         *resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
913         if (*resizeCoeff >= 16384L) {
914                 dev_err(ipu->dev, "Overflow on IC resize coefficient.\n");
915                 return -EINVAL;
916         }
917
918         dev_dbg(ipu->dev, "resizing from %u -> %u pixels, "
919                 "downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
920                 *downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
921                 ((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
922
923         return 0;
924 }
925
926 void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu)
927 {
928         uint32_t reg;
929         uint32_t mask_reg;
930
931         reg = ipu_vdi_read(ipu, VDI_C);
932         mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
933         if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
934                 reg &= ~VDI_C_TOP_FIELD_MAN_1;
935         else
936                 reg |= VDI_C_TOP_FIELD_MAN_1;
937
938         ipu_vdi_write(ipu, reg, VDI_C);
939 }