]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/ipu/arm/imx/v1_0/src/ipu_proc.c
TX51 pre-release
[karo-tx-redboot.git] / packages / devs / ipu / arm / imx / v1_0 / src / ipu_proc.c
1 //==========================================================================
2 //
3 //      IPU_COMMON.c
4 //
5 //      common functions definitions for IPU modules operation
6 //
7 //==========================================================================
8 //#####DESCRIPTIONBEGIN####
9 //
10 // Author(s):       Ray Sun <Yanfei.Sun@freescale.com>
11 // Create Date: 2008-07-31
12 //
13 //####DESCRIPTIONEND####
14 //
15 //==========================================================================
16
17 #include <string.h>
18 #include <cyg/io/ipu_common.h>
19 #include <cyg/io/xec_dls.h>
20
21 extern struct xec_dls_params xecDlsParams;
22
23 void ipu_ic_enable(int ic_enable, int irt_enable)
24 {
25         ipu_write_field(IPU_IPU_CONF__IC_EN, ic_enable);
26         ipu_write_field(IPU_IPU_CONF__IRT_EN, irt_enable);
27 }
28
29 /*
30 * this function is used to config the rotation/resizing task perform by the Image Converter
31 */
32 void ipu_ic_task_config(ipu_task_params_t task_params)
33 {
34         int resCoff, downsCoff;
35
36         switch (task_params.taskType) {
37         case PrP_ENC_TASK:
38                 ipu_write_field(IPU_IC_CONF__PRPENC_EN, 0);
39                 ipu_write_field(IPU_IC_CONF__RWS_EN, 1);
40                 ipu_write_field(IPU_IPU_FS_PROC_FLOW1__ENC_IN_VALID, 1);
41                 ipu_write_field(IPU_IC_IDMAC_1__CB0_BURST_16, 1);   // set to 16bps
42                 ipu_write_field(IPU_IC_IDMAC_1__CB6_BURST_16, 1);
43                 ipu_write_field(IPU_IC_CONF__PRPENC_EN, 1);
44                 ipu_write_field(IPU_IC_CONF__PRPENC_ROT_EN, task_params.rotEnable);
45                 /* set rotation task */
46                 if (task_params.rotEnable) {
47                         ipu_write_field(IPU_IC_IDMAC_1__T1_FLIP_LR, task_params.rotInfo.HorizFlip);
48                         ipu_write_field(IPU_IC_IDMAC_1__T1_FLIP_UD, task_params.rotInfo.VertFlip);
49                         ipu_write_field(IPU_IC_IDMAC_1__T1_ROT, task_params.rotInfo.rotation);
50                 }
51                 /* set resizing task */
52                 if (task_params.resEnable) {
53                         ipu_write_field(IPU_IC_IDMAC_2__T1_FR_HEIGHT, task_params.resInfo.outHeight - 1);
54                         ipu_write_field(IPU_IC_IDMAC_3__T1_FR_WIDTH, task_params.resInfo.outWidth - 1);
55
56                         ipu_ic_calc_resize_coeffs(task_params.resInfo.inWidth, task_params.resInfo.outWidth,
57                                                                         &resCoff, &downsCoff);
58                         ipu_write_field(IPU_IC_PRP_ENC_RSC__PRPENC_DS_R_H, downsCoff);
59                         ipu_write_field(IPU_IC_PRP_ENC_RSC__PRPENC_RS_R_H, resCoff);
60                         ipu_ic_calc_resize_coeffs(task_params.resInfo.inHeight, task_params.resInfo.outHeight,
61                                                                         &resCoff, &downsCoff);
62
63                         ipu_write_field(IPU_IC_PRP_ENC_RSC__PRPENC_DS_R_V, downsCoff);
64                         ipu_write_field(IPU_IC_PRP_ENC_RSC__PRPENC_RS_R_V, resCoff);
65                 }
66                 ipu_write_field(IPU_IC_CONF__PRPENC_EN, 1);
67                 break;
68
69         case PrP_VF_TASK:
70                 ipu_write_field(IPU_IC_CONF__PRPVF_EN, 0);
71                 ipu_write_field(IPU_IC_CONF__RWS_EN, 1);
72                 ipu_write_field(IPU_IPU_FS_PROC_FLOW1__VF_IN_VALID, 1);
73                 ipu_write_field(IPU_IC_IDMAC_1__CB1_BURST_16, 1);   // set to 16bps
74                 ipu_write_field(IPU_IC_IDMAC_1__CB6_BURST_16, 1);
75                 ipu_write_field(IPU_IC_CONF__PRPVF_EN, 1);
76                 ipu_write_field(IPU_IC_CONF__PRPVF_ROT_EN, task_params.rotEnable);
77                 // set rotation
78                 if (task_params.rotEnable) {
79                         ipu_write_field(IPU_IC_IDMAC_1__T2_FLIP_LR, task_params.rotInfo.HorizFlip);
80                         ipu_write_field(IPU_IC_IDMAC_1__T2_FLIP_UD, task_params.rotInfo.VertFlip);
81                         ipu_write_field(IPU_IC_IDMAC_1__T2_ROT, task_params.rotInfo.rotation);
82                 }
83                 // set resizing
84                 if (task_params.resEnable) {
85                         ipu_write_field(IPU_IC_IDMAC_2__T2_FR_HEIGHT, task_params.resInfo.outHeight - 1);
86                         ipu_write_field(IPU_IC_IDMAC_3__T2_FR_WIDTH, task_params.resInfo.outWidth - 1);
87
88                         ipu_ic_calc_resize_coeffs(task_params.resInfo.inWidth, task_params.resInfo.outWidth,
89                                                                         &resCoff, &downsCoff);
90                         ipu_write_field(IPU_IC_PRP_VF_RSC__PRPVF_DS_R_H, downsCoff);
91                         ipu_write_field(IPU_IC_PRP_VF_RSC__PRPVF_RS_R_H, resCoff);
92                         ipu_ic_calc_resize_coeffs(task_params.resInfo.inHeight, task_params.resInfo.outHeight,
93                                                                         &resCoff, &downsCoff);
94                         ipu_write_field(IPU_IC_PRP_VF_RSC__PRPVF_DS_R_V, downsCoff);
95                         ipu_write_field(IPU_IC_PRP_VF_RSC__PRPVF_RS_R_V, resCoff);
96                 }
97                 ipu_write_field(IPU_IC_CONF__PRPVF_EN, 1);
98                 break;
99
100         case PP_TASK:
101                 ipu_write_field(IPU_IC_CONF__PP_EN, 0);
102                 ipu_write_field(IPU_IC_IDMAC_1__CB2_BURST_16, 1);   // set to 16bps
103                 ipu_write_field(IPU_IC_IDMAC_1__CB5_BURST_16, 1);
104                 ipu_write_field(IPU_IC_CONF__PP_EN, 1);
105                 ipu_write_field(IPU_IC_CONF__PP_ROT_EN, task_params.rotEnable);
106                 // set rotation
107                 if (task_params.rotEnable) {
108                         ipu_write_field(IPU_IC_IDMAC_1__T3_FLIP_LR, task_params.rotInfo.HorizFlip);
109                         ipu_write_field(IPU_IC_IDMAC_1__T3_FLIP_UD, task_params.rotInfo.VertFlip);
110                         ipu_write_field(IPU_IC_IDMAC_1__T3_ROT, task_params.rotInfo.rotation);
111                 }
112                 // set resizing
113                 if (task_params.resEnable) {
114                         ipu_write_field(IPU_IC_IDMAC_2__T3_FR_HEIGHT, task_params.resInfo.outHeight - 1);
115                         ipu_write_field(IPU_IC_IDMAC_3__T3_FR_WIDTH, task_params.resInfo.outWidth - 1);
116
117                         ipu_ic_calc_resize_coeffs(task_params.resInfo.inWidth, task_params.resInfo.outWidth,
118                                                                         &resCoff, &downsCoff);
119
120                         ipu_write_field(IPU_IC_PP_RSC__PP_DS_R_H, downsCoff);
121                         ipu_write_field(IPU_IC_PP_RSC__PP_RS_R_H, resCoff);
122                         ipu_ic_calc_resize_coeffs(task_params.resInfo.inHeight, task_params.resInfo.outHeight,
123                                                                         &resCoff, &downsCoff);
124
125                         ipu_write_field(IPU_IC_PP_RSC__PP_DS_R_V, downsCoff);
126                         ipu_write_field(IPU_IC_PP_RSC__PP_RS_R_V, resCoff); // FROM (1536/2 -1)->479 *8192 = 13117
127                 }
128                 ipu_write_field(IPU_IC_CONF__PP_EN, 1);
129                 break;
130         default:
131                 ERRDP("Task type is wrong, IC task configuration failed\n");
132         }
133 }
134
135 /*
136 * this function is used to calculate the params for resizing
137 */
138 void ipu_ic_calc_resize_coeffs(unsigned int in_size, unsigned int out_size,
139                                                         unsigned int *resize_coeff, unsigned int *downsize_coeff)
140 {
141         unsigned int tempSize;
142         unsigned int tempDownsize;
143
144         /* Cannot downsize more than 8:1 */
145         if ((out_size << 3) < in_size)
146                 return;
147
148         /* compute downsizing coefficient */
149         tempDownsize = 0;
150         tempSize = in_size;
151         while ((tempSize >= out_size * 2) && (tempDownsize < 2)) {
152                 tempSize >>= 1;
153                 tempDownsize++;
154         }
155         *downsize_coeff = tempDownsize;
156
157         /* compute resizing coefficient using the following equation:
158            resizeCoeff = M*(SI -1)/(SO - 1)
159            where M = 2^13, SI - input size, SO - output size    */
160         *resize_coeff = (8192L * (tempSize - 1)) / (out_size - 1);
161         if (*resize_coeff >= 16384L) {
162                 ERRDP("Overflow on resize coeff.\n");
163                 *resize_coeff = 0x3FFF;
164         }
165 }
166
167 /*
168 * this function is used to set the resizing parameters
169 */
170 int ipu_ic_config_resize_rate(char *task_type, unsigned int res_vert, unsigned int down_vert,
171                                                         unsigned int res_horiz, unsigned int down_horiz)
172 {
173         unsigned int val;
174         val = (down_vert << 30) | (res_vert << 16) | (down_horiz << 14) | (res_horiz);
175
176         if (!strcmp(task_type, "PPTASK")) {
177                 DP("Post Processing Task!\n");
178                 writel(val, IPU_CTRL_BASE_ADDR + IPU_IC_PP_RSC__ADDR);
179         } else if (!strcmp(task_type, "VFTASK")) {
180                 DP("View Finder Task!\n");
181                 writel(val, IPU_CTRL_BASE_ADDR + IPU_IC_PRP_VF_RSC__ADDR);
182         } else if (!strcmp(task_type, "PrPTASK")) {
183                 DP("Pre Processing Task!\n");
184                 writel(val, IPU_CTRL_BASE_ADDR + IPU_IC_PRP_ENC_RSC__ADDR);
185         } else {
186                 ERRDP("Task type is not defined!\n");
187                 return -1;
188         }
189         return 0;
190 }
191
192 /*
193 * this function is used to calculate the output size for IC resizing task
194 */
195 void ipu_ic_calc_vout_size(ipu_res_info_t * info, display_device_t disp_device, int rotation,
196                                                 int full_screen_enable)
197 {
198         float coffHeight, coffWidth;
199
200         /* if rotation is enabled, swap the width and height */
201         if (rotation) {
202                 coffWidth = (float)(disp_device.height) / info->inWidth;
203                 coffHeight = (float)(disp_device.width) / info->inHeight;
204         } else {
205                 coffWidth = (float)(disp_device.width) / info->inWidth;
206                 coffHeight = (float)(disp_device.height) / info->inHeight;
207         }
208         /* the resizing ratio should be the same in both width and height */
209         if (coffWidth >= coffHeight) {
210                 info->outWidth = info->inWidth * coffHeight;
211                 info->outHeight = info->inHeight * coffHeight;
212         } else {
213                 info->outWidth = info->inWidth * coffWidth;
214                 info->outHeight = info->inHeight * coffWidth;
215         }
216
217         if (full_screen_enable) {
218                 if(rotation) {
219                         info->outWidth = disp_device.height;
220                         info->outHeight = disp_device.width;
221                 }
222                 else {
223                         info->outWidth = disp_device.width;
224                         info->outHeight = disp_device.height;
225                 }
226         }
227
228         /* the output of IPU resizing is up to 1024*1024 */
229         info->xSplitParts = info->outWidth / 1024 + 1;
230         info->ySplitParts = info->outHeight / 1024 + 1;
231
232         /* the image in block mode, which is 8*8 size */
233         info->outHeight -= info->outHeight % 8;
234         info->outWidth -= info->outWidth % 8;
235
236 }
237
238 /*
239 * this function is used to config the combination task in the IC
240 * local alpha with per-pixel or from separate buffer can be used
241 * global alpha can be used also.
242 */
243 int ipu_ic_combine_config(ic_comb_params_t comb_params)
244 {
245         switch (comb_params.taskType) {
246         case PrP_VF_TASK:
247                 ipu_write_field(IPU_IC_IDMAC_1__CB3_BURST_16, 1);   // set to 16bps
248                 if (comb_params.alpha < 0) {
249                         ipu_write_field(IPU_IC_CONF__IC_GLB_LOC_A, 0);  // local alpha with per-pixel
250                 } else if (comb_params.alpha < 0x100) {
251                         ipu_write_field(IPU_IC_CONF__IC_GLB_LOC_A, 1);  // global alpha enabled
252                         ipu_write_field(IPU_IC_CMBP_1__IC_PRPVF_ALPHA_V, comb_params.alpha);    // global alpha value
253                 } else {
254                         ipu_write_field(IPU_IC_CONF__IC_GLB_LOC_A, 0);  // local alpha from separate buffer
255                 }
256                 ipu_write_field(IPU_IC_CONF__PRPVF_CMB,
257                                                 (comb_params.alpha == 0) ? 0 : 1);
258                 ipu_write_field(IPU_IC_CONF__PRPVF_EN, 1);
259                 break;
260         case PP_TASK:
261                 ipu_write_field(IPU_IC_IDMAC_1__CB4_BURST_16, 1);   // set to 16bps
262                 if (comb_params.alpha < 0) {
263                         ipu_write_field(IPU_IC_CONF__IC_GLB_LOC_A, 0);  // local alpha with per-pixel
264                 } else if (comb_params.alpha < 0x100) {
265                         ipu_write_field(IPU_IC_CONF__IC_GLB_LOC_A, 1);  // global alpha enabled
266                         ipu_write_field(IPU_IC_CMBP_1__IC_PP_ALPHA_V, comb_params.alpha);   // global alpha
267                 } else {
268                         ipu_write_field(IPU_IC_CONF__IC_GLB_LOC_A, 0);  // local alpha in sepatate buffer
269                 }
270                 ipu_write_field(IPU_IC_CONF__PP_CMB,
271                                                 (comb_params.alpha == 0) ? 0 : 1);
272                 ipu_write_field(IPU_IC_CONF__PP_EN, 1);
273                 break;
274         default:
275                 ERRDP("Task Type is wrong!!\n");
276                 return -1;
277         }
278         return 0;
279 }
280
281 /*
282 * this function is used to config the color space conversion task in the IC
283 */
284 extern int xecDlsEnable;
285 int ipu_ic_csc_config(int csc_set_index, ic_csc_params_t csc_params)
286 {
287         unsigned int param;
288         CYG_ADDRESS tpmBaseAddr = IPU_CTRL_BASE_ADDR + 0x1F060000;
289         CYG_ADDRESS base;
290
291         if (csc_set_index != 1 && csc_set_index != 2) {
292                 ERRDP("Wrong index input for IC CSC!!\n");
293                 return -1;
294         }
295         /*Y = R *  .299 + G *  .587 + B *  .114;
296           U = R * -.169 + G * -.332 + B *  .500 + 128.;
297           V = R *  .500 + G * -.419 + B * -.0813 + 128.; */
298         unsigned int rgb2ycbcr_coeff[4][3] = {
299                 { 0x004D, 0x0096, 0x001D },
300                 { 0x01D5, 0x01AB, 0x0080 },
301                 { 0x0080, 0x0195, 0x01EB },
302                 { 0x0000, 0x0200, 0x0200 },   /* A0, A1, A2 */
303         };
304
305         /* transparent RGB->RGB matrix for combining
306          */
307         unsigned int rgb2rgb_coeff[4][3] = {
308                 { 0x0080, 0x0000, 0x0000 },
309                 { 0x0000, 0x0080, 0x0000 },
310                 { 0x0000, 0x0000, 0x0080 },
311                 { 0x0000, 0x0000, 0x0000 },   /* A0, A1, A2 */
312         };
313
314         /*
315           R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
316           G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
317           B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
318         */
319         unsigned int ycbcr2rgb_coeff[4][3] = {
320                 { 0x95, 0x0, 0xCC },
321                 { 0x95, 0x1CE, 0x198 },
322                 { 0x95, 0xFF, 0x0 },
323                 { 0x1E42, 0x10A, 0x1DD6 },    // A0, A1, A2
324         };
325
326         /*
327           R = (1.164 * alpha *  (Y - 16)) + (1.596 * (Cr - 128));
328           G = (1.164 * alpha * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
329           B = (1.164 * alpha * (Y - 16)) + (2.017 * (Cb - 128);
330         */
331         if (xecDlsEnable) {
332                 /* compensation of y_coeff */
333                 ycbcr2rgb_coeff[0][0] = ycbcr2rgb_coeff[0][0] * xecDlsParams.curAlpha/100;
334                 ycbcr2rgb_coeff[1][0] = ycbcr2rgb_coeff[1][0] * xecDlsParams.curAlpha/100;
335                 ycbcr2rgb_coeff[2][0] = ycbcr2rgb_coeff[2][0] * xecDlsParams.curAlpha/100;
336 #if 0
337                 /* compensation of constant coeff */
338                 ycbcr2rgb_coeff[3][0] -= (1.164 * 16 * 0x2 * (xecDlsParams.curAlpha - 100)/100);
339                 ycbcr2rgb_coeff[3][1] -= (1.164 * 16 * 0x2 * (xecDlsParams.curAlpha - 100)/100);
340                 ycbcr2rgb_coeff[3][2] -= (1.164 * 16 * 0x2 * (xecDlsParams.curAlpha - 100)/100);
341 #endif
342                 DP("alpha %d \n",       xecDlsParams.curAlpha);
343         }
344
345         if (csc_set_index == 1) {
346                 if (csc_params.taskType == PrP_ENC_TASK) {
347                         base = tpmBaseAddr + 0x2008;
348                 } else if (csc_params.taskType == PrP_VF_TASK) {
349                         base = tpmBaseAddr + 0x4028;
350                 } else if (csc_params.taskType == PP_TASK) {
351                         base = tpmBaseAddr + 0x6060;
352                 } else {
353                         ERRDP("Wrong task type for IC CSC1 input!!\n");
354                         return -1;
355                 }
356         } else {
357                 if (csc_params.taskType == PrP_VF_TASK) {
358                         base = tpmBaseAddr + 0x4040;
359                 } else if (csc_params.taskType == PP_TASK) {
360                         base = tpmBaseAddr + 0x6078;
361                 } else {
362                         ERRDP("Wrong task type for IC CSC2 input!!\n");
363                         return -1;
364                 }
365         }
366
367         if ((csc_params.inFormat == YCbCr) && (csc_params.outFormat == RGB)) {
368                 /* Init CSC (YCbCr->RGB) */
369                 param = (ycbcr2rgb_coeff[3][0] << 27) |
370                         (ycbcr2rgb_coeff[0][0] << 18) | (ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
371                 writel(param, base++);
372                 /* scale = 2, sat = 0 */
373                 param = (ycbcr2rgb_coeff[3][0] >> 5) | (2 << (40 - 32));
374                 writel(param, base++);
375
376                 param = (ycbcr2rgb_coeff[3][1] << 27) |
377                         (ycbcr2rgb_coeff[0][1] << 18) | (ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
378                 writel(param, base++);
379                 param = (ycbcr2rgb_coeff[3][1] >> 5);
380                 writel(param, base++);
381
382                 param = (ycbcr2rgb_coeff[3][2] << 27) |
383                         (ycbcr2rgb_coeff[0][2] << 18) | (ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
384                 writel(param, base++);
385                 param = (ycbcr2rgb_coeff[3][2] >> 5);
386                 writel(param, base++);
387         } else if ((csc_params.inFormat == RGB) && (csc_params.outFormat == YCbCr)) {
388                 /* Init CSC1 (RGB->YCbCr) */
389                 param = (rgb2ycbcr_coeff[3][0] << 27) |
390                         (rgb2ycbcr_coeff[0][0] << 18) | (rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
391                 writel(param, base++);
392                 /* scale = 1, sat = 0 */
393                 param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
394                 writel(param, base++);
395
396                 param = (rgb2ycbcr_coeff[3][1] << 27) |
397                         (rgb2ycbcr_coeff[0][1] << 18) | (rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
398                 writel(param, base++);
399                 param = (rgb2ycbcr_coeff[3][1] >> 5);
400                 writel(param, base++);
401
402                 param = (rgb2ycbcr_coeff[3][2] << 27) |
403                         (rgb2ycbcr_coeff[0][2] << 18) | (rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
404                 writel(param, base++);
405                 param = (rgb2ycbcr_coeff[3][2] >> 5);
406                 writel(param, base++);
407         } else if ((csc_params.inFormat == RGB) && (csc_params.outFormat == RGB)) {
408                 /* Init CSC1 */
409                 param =
410                         (rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
411                         (rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
412                 writel(param, base++);
413                 /* scale = 2, sat = 0 */
414                 param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
415                 writel(param, base++);
416
417                 param =
418                         (rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
419                         (rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
420                 writel(param, base++);
421                 param = (rgb2rgb_coeff[3][1] >> 5);
422                 writel(param, base++);
423
424                 param =
425                         (rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
426                         (rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
427                 writel(param, base++);
428                 param = (rgb2rgb_coeff[3][2] >> 5);
429                 writel(param, base++);
430         } else {
431                 ERRDP("Unkown color space conversion!!\n");
432                 return -1;
433         }
434         if (csc_set_index == 1) {
435                 if (csc_params.taskType == PrP_ENC_TASK) {
436                         ipu_write_field(IPU_IC_CONF__PRPENC_CSC1, 1);
437                 } else if (csc_params.taskType == PrP_VF_TASK) {
438                         ipu_write_field(IPU_IC_CONF__PRPVF_CSC1, 1);
439                 } else if (csc_params.taskType == PP_TASK) {
440                         ipu_write_field(IPU_IC_CONF__PP_CSC1, 1);
441                 } else {
442                         ERRDP("Wrong Task input!!\n");
443                         return -1;
444                 }
445         } else {
446                 if (csc_params.taskType == PrP_VF_TASK) {
447                         ipu_write_field(IPU_IC_CONF__PRPVF_CSC2, 1);
448                 } else if (csc_params.taskType == PP_TASK) {
449                         ipu_write_field(IPU_IC_CONF__PP_CSC2, 1);
450                 } else {
451                         ERRDP("Wrong Task input!!\n");
452                         return -1;
453                 }
454         }
455         return 0;
456 }
457
458 /*
459 * enable ipu tasks, such as preprocessing/post-processing task
460 */
461 int ipu_ic_task_enable(int task_type, int task, int enable)
462 {
463         switch (task_type) {
464         case PrP_ENC_TASK:
465                 if (task == IC_CSC1)
466                         ipu_write_field(IPU_IC_CONF__PRPENC_CSC1, enable);
467                 else if (IC_PRPENC)
468                         ipu_write_field(IPU_IC_CONF__PRPENC_EN, enable);
469                 else
470                         ERRDP("Task Type is wrong!!\n");
471                 break;
472         case PrP_VF_TASK:
473                 if (task == IC_CMB)
474                         ipu_write_field(IPU_IC_CONF__PRPVF_CMB, enable);
475                 else if (task == IC_CSC1)
476                         ipu_write_field(IPU_IC_CONF__PRPVF_CSC1, enable);
477                 else if (task == IC_CSC2)
478                         ipu_write_field(IPU_IC_CONF__PRPVF_CSC2, enable);
479                 else if (task == IC_PRPVF)
480                         ipu_write_field(IPU_IC_CONF__PRPVF_EN, enable);
481                 else
482                         ERRDP("Task Type is wrong!!\n");
483                 break;
484         case PP_TASK:
485                 if (task == IC_CMB)
486                         ipu_write_field(IPU_IC_CONF__PP_CMB, enable);
487                 else if (task == IC_CSC1)
488                         ipu_write_field(IPU_IC_CONF__PP_CSC1, enable);
489                 else if (task == IC_CSC2)
490                         ipu_write_field(IPU_IC_CONF__PP_CSC2, enable);
491                 else if (task == IC_PP)
492                         ipu_write_field(IPU_IC_CONF__PP_EN, enable);
493                 else
494                         ERRDP("Task Type is wrong!!\n");
495                 break;
496         default:
497                 ERRDP("Task Type is wrong!!\n");
498                 return -1;
499         }
500         return 0;
501 }
502
503 /*
504 * this function is used to config the color space conversion task in the DP
505 */
506 void ipu_dp_csc_config(int dp, dp_csc_param_t dp_csc_params, bool srm_mode_update)
507 {
508         int **coeff;
509
510         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_CSC_YUV_SAT_MODE_SYNC, 0); //SAT mode is zero
511         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_CSC_GAMUT_SAT_EN_SYNC, 0); //GAMUT en (RGB...)
512
513         if (dp_csc_params.mode >= 0) {
514                 ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_CSC_DEF_SYNC, dp_csc_params.mode); //disable CSC
515         }
516
517         coeff = dp_csc_params.coeff;
518
519         if (coeff) {
520                 writel(GET_LSB(10, coeff[0][0]) | (GET_LSB(10, coeff[0][1]) << 16),
521                         IPU_CTRL_BASE_ADDR + SRM_DP_CSCA_SYNC_0__ADDR + dp * 4);
522                 writel(GET_LSB(10, coeff[0][2]) | (GET_LSB(10, coeff[1][0]) << 16),
523                         IPU_CTRL_BASE_ADDR + SRM_DP_CSCA_SYNC_1__ADDR + dp * 4);
524                 writel(GET_LSB(10, coeff[1][1]) | (GET_LSB(10, coeff[1][2]) << 16),
525                         IPU_CTRL_BASE_ADDR + SRM_DP_CSCA_SYNC_2__ADDR + dp * 4);
526                 writel(GET_LSB(10, coeff[2][0]) | (GET_LSB(10, coeff[2][1]) << 16),
527                         IPU_CTRL_BASE_ADDR + SRM_DP_CSCA_SYNC_3__ADDR + dp * 4);
528                 writel(GET_LSB(10, coeff[2][2]) | (GET_LSB(14, coeff[3][0]) << 16) |
529                         (coeff[4][0] << 30), IPU_CTRL_BASE_ADDR + SRM_DP_CSC_SYNC_0__ADDR + dp * 4);
530                 writel(GET_LSB(14, coeff[3][1]) | (coeff[4][1] << 14) |
531                         (GET_LSB(14, coeff[3][2]) << 16) | (coeff[4][2] << 30),
532                         IPU_CTRL_BASE_ADDR + SRM_DP_CSC_SYNC_1__ADDR + dp * 4);
533         }
534         if (srm_mode_update) {
535                 ipu_write_field(IPU_IPU_SRM_PRI2__DP_S_SRM_MODE, 3);
536                 ipu_write_field(IPU_IPU_SRM_PRI2__DP_SRM_PRI, 0x0);
537         }
538 }
539
540 /*
541 * this function is used to config the foreground plane for combination in the DP
542 */
543 void ipu_dp_fg_config(dp_fg_param_t foreground_params)
544 {
545         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_GAMMA_EN_SYNC, 0);
546         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_GAMMA_YUV_EN_SYNC, 0);
547
548         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_COC_SYNC, foreground_params.cursorEnable);
549         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_GWCKE_SYNC, foreground_params.colorKeyEnable); //color key
550         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_GWAM_SYNC, foreground_params.alphaMode);   //1=global alpha,0=local alpha
551         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_GWSEL_SYNC, foreground_params.graphicSelect);  //1=graphic is FG,0=graphic is BG
552         ipu_write_field(SRM_DP_COM_CONF_SYNC__DP_FG_EN_SYNC, foreground_params.fgEnable);   //1=FG channel enabled,0=FG channel disabled
553         ipu_write_field(SRM_DP_FG_POS_SYNC__DP_FGXP_SYNC, foreground_params.offsetHoriz);
554         ipu_write_field(SRM_DP_FG_POS_SYNC__DP_FGYP_SYNC, foreground_params.offsetVert);
555         ipu_write_field(SRM_DP_GRAPH_WIND_CTRL_SYNC__DP_GWAV_SYNC, foreground_params.opaque);   // set the FG opaque
556         ipu_write_field(SRM_DP_GRAPH_WIND_CTRL_SYNC__DP_GWCKR_SYNC, 0xFF);
557         ipu_write_field(SRM_DP_GRAPH_WIND_CTRL_SYNC__DP_GWCKG_SYNC, 0xFF);
558         ipu_write_field(SRM_DP_GRAPH_WIND_CTRL_SYNC__DP_GWCKB_SYNC, 0xFF);
559 }
560
561 /*
562 * microcode configuration, refer to ipuv3 spec
563 */
564 void ipu_dc_microcode_config(dc_microcode_t microcode)
565 {
566         unsigned int LowWord = 0;
567         unsigned int HighWord = 0;
568         unsigned int opcode_fixed;
569
570         if (!strcmp(microcode.opcode, "WROD")) {
571                 LowWord = LowWord | microcode.sync;
572                 LowWord = LowWord | (microcode.gluelogic << 4);
573                 LowWord = LowWord | (microcode.waveform << 11);
574                 LowWord = LowWord | (microcode.mapping << 15);
575                 LowWord = LowWord | (microcode.operand << 20);
576
577                 HighWord = HighWord | (microcode.operand >> 12);
578                 opcode_fixed = 0x18 | (microcode.lf << 1);
579                 HighWord = HighWord | (opcode_fixed << 4);
580                 HighWord = HighWord | (microcode.stop << 9);
581         } else {
582                 ERRDP("Microcode type not supported yet!!\n");
583         }
584         writel(LowWord, IPU_CTRL_BASE_ADDR + IPU_MEM_DC_MICROCODE_BASE_ADDR + microcode.addr * 8);
585         writel(HighWord, IPU_CTRL_BASE_ADDR + IPU_MEM_DC_MICROCODE_BASE_ADDR + microcode.addr * 8 + 4);
586 }
587
588 /*
589 * microcode event configuration, to handle different event
590 */
591 void ipu_dc_microcode_event(int channel, char event[8], int priority, int address)
592 {
593         int channel_offset = (channel >= 5) ? (0x5C + (channel - 5) * 0x1C) : channel * 0x1C;
594
595         if (!strcmp(event, "NL")) {
596                 ipu_write_field(channel_offset + IPU_DC_RL0_CH_0__COD_NL_START_CHAN_0, address);
597                 ipu_write_field(channel_offset + IPU_DC_RL0_CH_0__COD_NL_PRIORITY_CHAN_0, priority);
598         } else if (!strcmp(event, "NF")) {
599                 ipu_write_field(channel_offset + IPU_DC_RL0_CH_0__COD_NF_START_CHAN_0, address);
600                 ipu_write_field(channel_offset + IPU_DC_RL0_CH_0__COD_NF_PRIORITY_CHAN_0, priority);
601         } else if (!strcmp(event, "NFIELD")) {
602                 ipu_write_field(channel_offset + IPU_DC_RL1_CH_0__COD_NFIELD_START_CHAN_0, address);
603                 ipu_write_field(channel_offset + IPU_DC_RL1_CH_0__COD_NFIELD_PRIORITY_CHAN_0, priority);
604         } else if (!strcmp(event, "EOF")) {
605                 ipu_write_field(channel_offset + IPU_DC_RL1_CH_0__COD_EOF_START_CHAN_0, address);
606                 ipu_write_field(channel_offset + IPU_DC_RL1_CH_0__COD_EOF_PRIORITY_CHAN_0, priority);
607         } else if (!strcmp(event, "EOFIELD")) {
608                 ipu_write_field(channel_offset + IPU_DC_RL2_CH_0__COD_EOFIELD_START_CHAN_0, address);
609                 ipu_write_field(channel_offset + IPU_DC_RL2_CH_0__COD_EOFIELD_PRIORITY_CHAN_0, priority);
610         } else if (!strcmp(event, "EOL")) {
611                 ipu_write_field(channel_offset + IPU_DC_RL2_CH_0__COD_EOL_START_CHAN_0, address);
612                 ipu_write_field(channel_offset + IPU_DC_RL2_CH_0__COD_EOL_PRIORITY_CHAN_0, priority);
613         } else if (!strcmp(event, "NEW_CHAN")) {
614                 ipu_write_field(channel_offset + IPU_DC_RL3_CH_0__COD_NEW_CHAN_START_CHAN_0, address);
615                 ipu_write_field(channel_offset + IPU_DC_RL3_CH_0__COD_NEW_CHAN_PRIORITY_CHAN_0, priority);
616         } else if (!strcmp(event, "NEW_ADDR")) {
617                 ipu_write_field(channel_offset + IPU_DC_RL3_CH_0__COD_NEW_ADDR_START_CHAN_0, address);
618                 ipu_write_field(channel_offset + IPU_DC_RL3_CH_0__COD_NEW_ADDR_PRIORITY_CHAN_0, priority);
619         } else if (!strcmp(event, "NEW_DATA")) {
620                 ipu_write_field(channel_offset + IPU_DC_RL4_CH_0__COD_NEW_DATA_START_CHAN_0, address);
621                 ipu_write_field(channel_offset + IPU_DC_RL4_CH_0__COD_NEW_DATA_PRIORITY_CHAN_0, priority);
622         } else {
623                 ERRDP("Wrong DC microcode\n");
624         }
625 }
626
627 /*
628 * this function is used to perform pack/unpacking for yuv/rgb data
629 */
630 int ipu_dc_map(int map, int format)
631 {
632         int offset[3], mask[3];
633
634         if (format == RGB565) {
635                 offset[0] = 15;
636                 mask[0] = 0xF8;
637                 offset[1] = 10;
638                 mask[1] = 0xFC;
639                 offset[2] = 4;
640                 mask[2] = 0xF8;
641         } else if (format == RGB666) {
642                 offset[0] = 17;
643                 mask[0] = 0xFC;
644                 offset[1] = 11;
645                 mask[1] = 0xFC;
646                 offset[2] = 5;
647                 mask[2] = 0xFC;
648         } else if (format == RGB888 || format == YUV888) {
649                 offset[0] = 23;
650                 mask[0] = 0xFF;
651                 offset[1] = 15;
652                 mask[1] = 0xFF;
653                 offset[2] = 7;
654                 mask[2] = 0xFF;
655         } else {
656                 ERRDP("Invalid pixel format %d\n", format);
657                 return -1;
658         }
659
660         switch (map) {
661         case 0:
662                 /* DC_MAP, should be RGB666 mode */
663                 ipu_write_field(IPU_DC_MAP_CONF_16__MD_OFFSET_2, offset[0]);
664                 ipu_write_field(IPU_DC_MAP_CONF_16__MD_MASK_2, mask[0]);
665                 ipu_write_field(IPU_DC_MAP_CONF_15__MD_OFFSET_1, offset[1]);
666                 ipu_write_field(IPU_DC_MAP_CONF_15__MD_MASK_1, mask[1]);
667                 ipu_write_field(IPU_DC_MAP_CONF_15__MD_OFFSET_0, offset[2]);
668                 ipu_write_field(IPU_DC_MAP_CONF_15__MD_MASK_0, mask[2]);
669
670                 ipu_write_field(IPU_DC_MAP_CONF_0__MAPPING_PNTR_BYTE2_0, 0);
671                 ipu_write_field(IPU_DC_MAP_CONF_0__MAPPING_PNTR_BYTE1_0, 2);
672                 ipu_write_field(IPU_DC_MAP_CONF_0__MAPPING_PNTR_BYTE0_0, 1);
673                 break;
674
675         case 1:
676                 /* DC_MAP */
677                 ipu_write_field(IPU_DC_MAP_CONF_18__MD_OFFSET_6, offset[0]);
678                 ipu_write_field(IPU_DC_MAP_CONF_18__MD_MASK_6, mask[0]);
679                 ipu_write_field(IPU_DC_MAP_CONF_17__MD_OFFSET_5, offset[1]);
680                 ipu_write_field(IPU_DC_MAP_CONF_17__MD_MASK_5, mask[1]);
681                 ipu_write_field(IPU_DC_MAP_CONF_17__MD_OFFSET_4, offset[2]);
682                 ipu_write_field(IPU_DC_MAP_CONF_17__MD_MASK_4, mask[2]);
683                 ipu_write_field(IPU_DC_MAP_CONF_0__MAPPING_PNTR_BYTE2_1, 6);
684                 ipu_write_field(IPU_DC_MAP_CONF_0__MAPPING_PNTR_BYTE1_1, 5);
685                 ipu_write_field(IPU_DC_MAP_CONF_0__MAPPING_PNTR_BYTE0_1, 4);
686                 break;
687
688         default:
689                 ERRDP("Invalid map value: %d\n", map);
690                 return -1;
691         }
692         return 0;
693 }
694
695 /*
696 *  config the display port in the DC
697 */
698 int ipu_dc_display_config(int display_port, int type, int increment, int strideline)
699 {
700         switch (display_port) {
701         case 0:
702                 ipu_write_field(IPU_DC_DISP_CONF1_0__DISP_TYP_0, type); /* parallel display without byte enable */
703                 ipu_write_field(IPU_DC_DISP_CONF1_0__ADDR_INCREMENT_0, increment);
704                 ipu_write_field(IPU_DC_DISP_CONF2_0__SL_0, strideline); //stride line
705                 break;
706         case 1:
707                 ipu_write_field(IPU_DC_DISP_CONF1_1__DISP_TYP_1, type); /* parallel display without byte enable */
708                 ipu_write_field(IPU_DC_DISP_CONF1_1__ADDR_INCREMENT_1, increment);
709                 ipu_write_field(IPU_DC_DISP_CONF2_1__SL_1, strideline); //stride line
710                 break;
711         case 2:
712                 ipu_write_field(IPU_DC_DISP_CONF1_2__DISP_TYP_2, type); /* parallel display without byte enable */
713                 ipu_write_field(IPU_DC_DISP_CONF1_2__ADDR_INCREMENT_2, increment);
714                 ipu_write_field(IPU_DC_DISP_CONF2_2__SL_2, strideline); //stride line
715                 break;
716         case 3:
717                 ipu_write_field(IPU_DC_DISP_CONF1_3__DISP_TYP_3, type); /* parallel display without byte enable */
718                 ipu_write_field(IPU_DC_DISP_CONF1_3__ADDR_INCREMENT_3, increment);
719                 ipu_write_field(IPU_DC_DISP_CONF2_3__SL_3, strideline); //stride line
720                 break;
721         default:
722                 ERRDP("Invalid display port: %d\n", display_port);
723                 return -1;
724         }
725         return 0;
726 }
727
728 /*
729 * config the write channel for display.
730 * different channels linked to different display port
731 */
732 int ipu_dc_write_channel_config(int dma_channel, int disp_port, int link_di_index,
733                                                                 int field_mode_enable)
734 {
735         switch (dma_channel) {
736         case 23:
737                 ipu_write_field(IPU_DC_WR_CH_CONF_5__PROG_START_TIME_5, 0);
738                 ipu_write_field(IPU_DC_WR_CH_CONF_5__CHAN_MASK_DEFAULT_5, 0);
739                 ipu_write_field(IPU_DC_WR_CH_CONF_5__PROG_CHAN_TYP_5, 4);   // Normal mode without anti-tearing
740                 ipu_write_field(IPU_DC_WR_CH_CONF_5__PROG_DISP_ID_5, disp_port);
741                 ipu_write_field(IPU_DC_WR_CH_CONF_5__PROG_DI_ID_5, link_di_index);
742                 ipu_write_field(IPU_DC_WR_CH_CONF_5__W_SIZE_5, 2);  // Component size access to DC set to 24bit
743                 ipu_write_field(IPU_DC_WR_CH_ADDR_5__ST_ADDR_5, 0);
744                 ipu_write_field(IPU_DC_WR_CH_CONF_5__FIELD_MODE_5, field_mode_enable);
745
746                 ipu_write_field(IPU_DC_GEN__SYNC_PRIORITY_5, 1);    // sets the priority of channel #5 to high.
747                 ipu_write_field(IPU_DC_GEN__MASK4CHAN_5, 0);    // mask channel is associated to the sync flow via DC (without DP)
748                 ipu_write_field(IPU_DC_GEN__MASK_EN, 0);    // mask channel is disabled
749                 ipu_write_field(IPU_DC_GEN__DC_CH5_TYPE, 0);    // alternate sync or asyn flow
750                 break;
751         case 28:
752                 ipu_write_field(IPU_DC_WR_CH_CONF_1__PROG_START_TIME_1, 0);
753                 ipu_write_field(IPU_DC_WR_CH_CONF_1__CHAN_MASK_DEFAULT_1, 0);
754                 ipu_write_field(IPU_DC_WR_CH_CONF_1__PROG_CHAN_TYP_1, 4);   // Normal mode without anti-tearing
755                 ipu_write_field(IPU_DC_WR_CH_CONF_1__PROG_DISP_ID_1, disp_port);
756                 ipu_write_field(IPU_DC_WR_CH_CONF_1__PROG_DI_ID_1, link_di_index);
757                 /* if CH28 is connected to DI0, CH23 must connect to DI1 even if it is not used. */
758                 if (link_di_index == 0)
759                         ipu_write_field(IPU_DC_WR_CH_CONF_5__PROG_DI_ID_5, 1);
760
761                 ipu_write_field(IPU_DC_WR_CH_CONF_1__W_SIZE_1, 2);  // Component size access to DC set to 24bit
762                 ipu_write_field(IPU_DC_WR_CH_ADDR_1__ST_ADDR_1, 0); // START ADDRESS OF CHANNEL
763                 ipu_write_field(IPU_DC_WR_CH_CONF_1__FIELD_MODE_1, field_mode_enable);
764
765                 ipu_write_field(IPU_DC_GEN__SYNC_PRIORITY_1, 1);    //sets the priority of channel #5 to high.
766                 ipu_write_field(IPU_DC_GEN__SYNC_1_6, 2);   // Channel 1 of the DC handles sync flow
767                 break;
768         default:
769                 ERRDP("Invalid display channel: %d\n", dma_channel);
770                 return -1;
771         }
772         return 0;
773 }
774