xref: /linux/drivers/gpu/ipu-v3/ipu-ic.c (revision e58e871becec2d3b04ed91c0c16fe8deac9c9dfa)
1 /*
2  * Copyright (C) 2012-2014 Mentor Graphics Inc.
3  * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
4  *
5  * The code contained herein is licensed under the GNU General Public
6  * License. You may obtain a copy of the GNU General Public License
7  * Version 2 or later at the following locations:
8  *
9  * http://www.opensource.org/licenses/gpl-license.html
10  * http://www.gnu.org/copyleft/gpl.html
11  */
12 
13 #include <linux/types.h>
14 #include <linux/init.h>
15 #include <linux/errno.h>
16 #include <linux/spinlock.h>
17 #include <linux/bitrev.h>
18 #include <linux/io.h>
19 #include <linux/err.h>
20 #include "ipu-prv.h"
21 
22 /* IC Register Offsets */
23 #define IC_CONF                 0x0000
24 #define IC_PRP_ENC_RSC          0x0004
25 #define IC_PRP_VF_RSC           0x0008
26 #define IC_PP_RSC               0x000C
27 #define IC_CMBP_1               0x0010
28 #define IC_CMBP_2               0x0014
29 #define IC_IDMAC_1              0x0018
30 #define IC_IDMAC_2              0x001C
31 #define IC_IDMAC_3              0x0020
32 #define IC_IDMAC_4              0x0024
33 
34 /* IC Register Fields */
35 #define IC_CONF_PRPENC_EN       (1 << 0)
36 #define IC_CONF_PRPENC_CSC1     (1 << 1)
37 #define IC_CONF_PRPENC_ROT_EN   (1 << 2)
38 #define IC_CONF_PRPVF_EN        (1 << 8)
39 #define IC_CONF_PRPVF_CSC1      (1 << 9)
40 #define IC_CONF_PRPVF_CSC2      (1 << 10)
41 #define IC_CONF_PRPVF_CMB       (1 << 11)
42 #define IC_CONF_PRPVF_ROT_EN    (1 << 12)
43 #define IC_CONF_PP_EN           (1 << 16)
44 #define IC_CONF_PP_CSC1         (1 << 17)
45 #define IC_CONF_PP_CSC2         (1 << 18)
46 #define IC_CONF_PP_CMB          (1 << 19)
47 #define IC_CONF_PP_ROT_EN       (1 << 20)
48 #define IC_CONF_IC_GLB_LOC_A    (1 << 28)
49 #define IC_CONF_KEY_COLOR_EN    (1 << 29)
50 #define IC_CONF_RWS_EN          (1 << 30)
51 #define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
52 
53 #define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
54 #define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
55 #define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
56 #define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
57 #define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
58 #define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
59 #define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
60 #define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
61 #define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
62 #define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
63 #define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
64 #define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
65 #define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
66 #define IC_IDMAC_1_PP_ROT_OFFSET        17
67 #define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
68 #define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
69 #define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
70 
71 #define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
72 #define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
73 #define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
74 #define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
75 #define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
76 #define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
77 
78 #define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
79 #define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
80 #define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
81 #define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
82 #define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
83 #define IC_IDMAC_3_PP_WIDTH_OFFSET      20
84 
85 struct ic_task_regoffs {
86 	u32 rsc;
87 	u32 tpmem_csc[2];
88 };
89 
90 struct ic_task_bitfields {
91 	u32 ic_conf_en;
92 	u32 ic_conf_rot_en;
93 	u32 ic_conf_cmb_en;
94 	u32 ic_conf_csc1_en;
95 	u32 ic_conf_csc2_en;
96 	u32 ic_cmb_galpha_bit;
97 };
98 
99 static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
100 	[IC_TASK_ENCODER] = {
101 		.rsc = IC_PRP_ENC_RSC,
102 		.tpmem_csc = {0x2008, 0},
103 	},
104 	[IC_TASK_VIEWFINDER] = {
105 		.rsc = IC_PRP_VF_RSC,
106 		.tpmem_csc = {0x4028, 0x4040},
107 	},
108 	[IC_TASK_POST_PROCESSOR] = {
109 		.rsc = IC_PP_RSC,
110 		.tpmem_csc = {0x6060, 0x6078},
111 	},
112 };
113 
114 static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
115 	[IC_TASK_ENCODER] = {
116 		.ic_conf_en = IC_CONF_PRPENC_EN,
117 		.ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
118 		.ic_conf_cmb_en = 0,    /* NA */
119 		.ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
120 		.ic_conf_csc2_en = 0,   /* NA */
121 		.ic_cmb_galpha_bit = 0, /* NA */
122 	},
123 	[IC_TASK_VIEWFINDER] = {
124 		.ic_conf_en = IC_CONF_PRPVF_EN,
125 		.ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
126 		.ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
127 		.ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
128 		.ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
129 		.ic_cmb_galpha_bit = 0,
130 	},
131 	[IC_TASK_POST_PROCESSOR] = {
132 		.ic_conf_en = IC_CONF_PP_EN,
133 		.ic_conf_rot_en = IC_CONF_PP_ROT_EN,
134 		.ic_conf_cmb_en = IC_CONF_PP_CMB,
135 		.ic_conf_csc1_en = IC_CONF_PP_CSC1,
136 		.ic_conf_csc2_en = IC_CONF_PP_CSC2,
137 		.ic_cmb_galpha_bit = 8,
138 	},
139 };
140 
141 struct ipu_ic_priv;
142 
143 struct ipu_ic {
144 	enum ipu_ic_task task;
145 	const struct ic_task_regoffs *reg;
146 	const struct ic_task_bitfields *bit;
147 
148 	enum ipu_color_space in_cs, g_in_cs;
149 	enum ipu_color_space out_cs;
150 	bool graphics;
151 	bool rotation;
152 	bool in_use;
153 
154 	struct ipu_ic_priv *priv;
155 };
156 
157 struct ipu_ic_priv {
158 	void __iomem *base;
159 	void __iomem *tpmem_base;
160 	spinlock_t lock;
161 	struct ipu_soc *ipu;
162 	int use_count;
163 	int irt_use_count;
164 	struct ipu_ic task[IC_NUM_TASKS];
165 };
166 
167 static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
168 {
169 	return readl(ic->priv->base + offset);
170 }
171 
172 static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
173 {
174 	writel(value, ic->priv->base + offset);
175 }
176 
177 struct ic_csc_params {
178 	s16 coeff[3][3];	/* signed 9-bit integer coefficients */
179 	s16 offset[3];		/* signed 11+2-bit fixed point offset */
180 	u8 scale:2;		/* scale coefficients * 2^(scale-1) */
181 	bool sat:1;		/* saturate to (16, 235(Y) / 240(U, V)) */
182 };
183 
184 /*
185  * Y = R *  .299 + G *  .587 + B *  .114;
186  * U = R * -.169 + G * -.332 + B *  .500 + 128.;
187  * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
188  */
189 static const struct ic_csc_params ic_csc_rgb2ycbcr = {
190 	.coeff = {
191 		{ 77, 150, 29 },
192 		{ 469, 427, 128 },
193 		{ 128, 405, 491 },
194 	},
195 	.offset = { 0, 512, 512 },
196 	.scale = 1,
197 };
198 
199 /* transparent RGB->RGB matrix for graphics combining */
200 static const struct ic_csc_params ic_csc_rgb2rgb = {
201 	.coeff = {
202 		{ 128, 0, 0 },
203 		{ 0, 128, 0 },
204 		{ 0, 0, 128 },
205 	},
206 	.scale = 2,
207 };
208 
209 /*
210  * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
211  * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
212  * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
213  */
214 static const struct ic_csc_params ic_csc_ycbcr2rgb = {
215 	.coeff = {
216 		{ 149, 0, 204 },
217 		{ 149, 462, 408 },
218 		{ 149, 255, 0 },
219 	},
220 	.offset = { -446, 266, -554 },
221 	.scale = 2,
222 };
223 
224 static int init_csc(struct ipu_ic *ic,
225 		    enum ipu_color_space inf,
226 		    enum ipu_color_space outf,
227 		    int csc_index)
228 {
229 	struct ipu_ic_priv *priv = ic->priv;
230 	const struct ic_csc_params *params;
231 	u32 __iomem *base;
232 	const u16 (*c)[3];
233 	const u16 *a;
234 	u32 param;
235 
236 	base = (u32 __iomem *)
237 		(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
238 
239 	if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
240 		params = &ic_csc_ycbcr2rgb;
241 	else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
242 		params = &ic_csc_rgb2ycbcr;
243 	else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
244 		params = &ic_csc_rgb2rgb;
245 	else {
246 		dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
247 		return -EINVAL;
248 	}
249 
250 	/* Cast to unsigned */
251 	c = (const u16 (*)[3])params->coeff;
252 	a = (const u16 *)params->offset;
253 
254 	param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
255 		((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
256 	writel(param, base++);
257 
258 	param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
259 		(params->sat << 9);
260 	writel(param, base++);
261 
262 	param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
263 		((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
264 	writel(param, base++);
265 
266 	param = ((a[1] & 0x1fe0) >> 5);
267 	writel(param, base++);
268 
269 	param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
270 		((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
271 	writel(param, base++);
272 
273 	param = ((a[2] & 0x1fe0) >> 5);
274 	writel(param, base++);
275 
276 	return 0;
277 }
278 
279 static int calc_resize_coeffs(struct ipu_ic *ic,
280 			      u32 in_size, u32 out_size,
281 			      u32 *resize_coeff,
282 			      u32 *downsize_coeff)
283 {
284 	struct ipu_ic_priv *priv = ic->priv;
285 	struct ipu_soc *ipu = priv->ipu;
286 	u32 temp_size, temp_downsize;
287 
288 	/*
289 	 * Input size cannot be more than 4096, and output size cannot
290 	 * be more than 1024
291 	 */
292 	if (in_size > 4096) {
293 		dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
294 		return -EINVAL;
295 	}
296 	if (out_size > 1024) {
297 		dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
298 		return -EINVAL;
299 	}
300 
301 	/* Cannot downsize more than 4:1 */
302 	if ((out_size << 2) < in_size) {
303 		dev_err(ipu->dev, "Unsupported downsize\n");
304 		return -EINVAL;
305 	}
306 
307 	/* Compute downsizing coefficient */
308 	temp_downsize = 0;
309 	temp_size = in_size;
310 	while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
311 	       (temp_downsize < 2)) {
312 		temp_size >>= 1;
313 		temp_downsize++;
314 	}
315 	*downsize_coeff = temp_downsize;
316 
317 	/*
318 	 * compute resizing coefficient using the following equation:
319 	 * resize_coeff = M * (SI - 1) / (SO - 1)
320 	 * where M = 2^13, SI = input size, SO = output size
321 	 */
322 	*resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
323 	if (*resize_coeff >= 16384L) {
324 		dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
325 		*resize_coeff = 0x3FFF;
326 	}
327 
328 	return 0;
329 }
330 
331 void ipu_ic_task_enable(struct ipu_ic *ic)
332 {
333 	struct ipu_ic_priv *priv = ic->priv;
334 	unsigned long flags;
335 	u32 ic_conf;
336 
337 	spin_lock_irqsave(&priv->lock, flags);
338 
339 	ic_conf = ipu_ic_read(ic, IC_CONF);
340 
341 	ic_conf |= ic->bit->ic_conf_en;
342 
343 	if (ic->rotation)
344 		ic_conf |= ic->bit->ic_conf_rot_en;
345 
346 	if (ic->in_cs != ic->out_cs)
347 		ic_conf |= ic->bit->ic_conf_csc1_en;
348 
349 	if (ic->graphics) {
350 		ic_conf |= ic->bit->ic_conf_cmb_en;
351 		ic_conf |= ic->bit->ic_conf_csc1_en;
352 
353 		if (ic->g_in_cs != ic->out_cs)
354 			ic_conf |= ic->bit->ic_conf_csc2_en;
355 	}
356 
357 	ipu_ic_write(ic, ic_conf, IC_CONF);
358 
359 	spin_unlock_irqrestore(&priv->lock, flags);
360 }
361 EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
362 
363 void ipu_ic_task_disable(struct ipu_ic *ic)
364 {
365 	struct ipu_ic_priv *priv = ic->priv;
366 	unsigned long flags;
367 	u32 ic_conf;
368 
369 	spin_lock_irqsave(&priv->lock, flags);
370 
371 	ic_conf = ipu_ic_read(ic, IC_CONF);
372 
373 	ic_conf &= ~(ic->bit->ic_conf_en |
374 		     ic->bit->ic_conf_csc1_en |
375 		     ic->bit->ic_conf_rot_en);
376 	if (ic->bit->ic_conf_csc2_en)
377 		ic_conf &= ~ic->bit->ic_conf_csc2_en;
378 	if (ic->bit->ic_conf_cmb_en)
379 		ic_conf &= ~ic->bit->ic_conf_cmb_en;
380 
381 	ipu_ic_write(ic, ic_conf, IC_CONF);
382 
383 	spin_unlock_irqrestore(&priv->lock, flags);
384 }
385 EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
386 
387 int ipu_ic_task_graphics_init(struct ipu_ic *ic,
388 			      enum ipu_color_space in_g_cs,
389 			      bool galpha_en, u32 galpha,
390 			      bool colorkey_en, u32 colorkey)
391 {
392 	struct ipu_ic_priv *priv = ic->priv;
393 	unsigned long flags;
394 	u32 reg, ic_conf;
395 	int ret = 0;
396 
397 	if (ic->task == IC_TASK_ENCODER)
398 		return -EINVAL;
399 
400 	spin_lock_irqsave(&priv->lock, flags);
401 
402 	ic_conf = ipu_ic_read(ic, IC_CONF);
403 
404 	if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
405 		/* need transparent CSC1 conversion */
406 		ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
407 			       IPUV3_COLORSPACE_RGB, 0);
408 		if (ret)
409 			goto unlock;
410 	}
411 
412 	ic->g_in_cs = in_g_cs;
413 
414 	if (ic->g_in_cs != ic->out_cs) {
415 		ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
416 		if (ret)
417 			goto unlock;
418 	}
419 
420 	if (galpha_en) {
421 		ic_conf |= IC_CONF_IC_GLB_LOC_A;
422 		reg = ipu_ic_read(ic, IC_CMBP_1);
423 		reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
424 		reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
425 		ipu_ic_write(ic, reg, IC_CMBP_1);
426 	} else
427 		ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
428 
429 	if (colorkey_en) {
430 		ic_conf |= IC_CONF_KEY_COLOR_EN;
431 		ipu_ic_write(ic, colorkey, IC_CMBP_2);
432 	} else
433 		ic_conf &= ~IC_CONF_KEY_COLOR_EN;
434 
435 	ipu_ic_write(ic, ic_conf, IC_CONF);
436 
437 	ic->graphics = true;
438 unlock:
439 	spin_unlock_irqrestore(&priv->lock, flags);
440 	return ret;
441 }
442 EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
443 
444 int ipu_ic_task_init(struct ipu_ic *ic,
445 		     int in_width, int in_height,
446 		     int out_width, int out_height,
447 		     enum ipu_color_space in_cs,
448 		     enum ipu_color_space out_cs)
449 {
450 	struct ipu_ic_priv *priv = ic->priv;
451 	u32 reg, downsize_coeff, resize_coeff;
452 	unsigned long flags;
453 	int ret = 0;
454 
455 	/* Setup vertical resizing */
456 	ret = calc_resize_coeffs(ic, in_height, out_height,
457 				 &resize_coeff, &downsize_coeff);
458 	if (ret)
459 		return ret;
460 
461 	reg = (downsize_coeff << 30) | (resize_coeff << 16);
462 
463 	/* Setup horizontal resizing */
464 	ret = calc_resize_coeffs(ic, in_width, out_width,
465 				 &resize_coeff, &downsize_coeff);
466 	if (ret)
467 		return ret;
468 
469 	reg |= (downsize_coeff << 14) | resize_coeff;
470 
471 	spin_lock_irqsave(&priv->lock, flags);
472 
473 	ipu_ic_write(ic, reg, ic->reg->rsc);
474 
475 	/* Setup color space conversion */
476 	ic->in_cs = in_cs;
477 	ic->out_cs = out_cs;
478 
479 	if (ic->in_cs != ic->out_cs) {
480 		ret = init_csc(ic, ic->in_cs, ic->out_cs, 0);
481 		if (ret)
482 			goto unlock;
483 	}
484 
485 unlock:
486 	spin_unlock_irqrestore(&priv->lock, flags);
487 	return ret;
488 }
489 EXPORT_SYMBOL_GPL(ipu_ic_task_init);
490 
491 int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
492 			  u32 width, u32 height, int burst_size,
493 			  enum ipu_rotate_mode rot)
494 {
495 	struct ipu_ic_priv *priv = ic->priv;
496 	struct ipu_soc *ipu = priv->ipu;
497 	u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
498 	u32 temp_rot = bitrev8(rot) >> 5;
499 	bool need_hor_flip = false;
500 	unsigned long flags;
501 	int ret = 0;
502 
503 	if ((burst_size != 8) && (burst_size != 16)) {
504 		dev_err(ipu->dev, "Illegal burst length for IC\n");
505 		return -EINVAL;
506 	}
507 
508 	width--;
509 	height--;
510 
511 	if (temp_rot & 0x2)	/* Need horizontal flip */
512 		need_hor_flip = true;
513 
514 	spin_lock_irqsave(&priv->lock, flags);
515 
516 	ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
517 	ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
518 	ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
519 
520 	switch (channel->num) {
521 	case IPUV3_CHANNEL_IC_PP_MEM:
522 		if (burst_size == 16)
523 			ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
524 		else
525 			ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
526 
527 		if (need_hor_flip)
528 			ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
529 		else
530 			ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
531 
532 		ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
533 		ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
534 
535 		ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
536 		ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
537 		break;
538 	case IPUV3_CHANNEL_MEM_IC_PP:
539 		if (burst_size == 16)
540 			ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
541 		else
542 			ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
543 		break;
544 	case IPUV3_CHANNEL_MEM_ROT_PP:
545 		ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
546 		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
547 		break;
548 	case IPUV3_CHANNEL_MEM_IC_PRP_VF:
549 		if (burst_size == 16)
550 			ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
551 		else
552 			ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
553 		break;
554 	case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
555 		if (burst_size == 16)
556 			ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
557 		else
558 			ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
559 
560 		if (need_hor_flip)
561 			ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
562 		else
563 			ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
564 
565 		ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
566 		ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
567 
568 		ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
569 		ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
570 		break;
571 	case IPUV3_CHANNEL_MEM_ROT_ENC:
572 		ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
573 		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
574 		break;
575 	case IPUV3_CHANNEL_IC_PRP_VF_MEM:
576 		if (burst_size == 16)
577 			ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
578 		else
579 			ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
580 
581 		if (need_hor_flip)
582 			ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
583 		else
584 			ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
585 
586 		ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
587 		ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
588 
589 		ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
590 		ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
591 		break;
592 	case IPUV3_CHANNEL_MEM_ROT_VF:
593 		ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
594 		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
595 		break;
596 	case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
597 		if (burst_size == 16)
598 			ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
599 		else
600 			ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
601 		break;
602 	case IPUV3_CHANNEL_G_MEM_IC_PP:
603 		if (burst_size == 16)
604 			ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
605 		else
606 			ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
607 		break;
608 	case IPUV3_CHANNEL_VDI_MEM_IC_VF:
609 		if (burst_size == 16)
610 			ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
611 		else
612 			ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
613 		break;
614 	default:
615 		goto unlock;
616 	}
617 
618 	ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
619 	ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
620 	ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
621 
622 	if (ipu_rot_mode_is_irt(rot))
623 		ic->rotation = true;
624 
625 unlock:
626 	spin_unlock_irqrestore(&priv->lock, flags);
627 	return ret;
628 }
629 EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
630 
631 static void ipu_irt_enable(struct ipu_ic *ic)
632 {
633 	struct ipu_ic_priv *priv = ic->priv;
634 
635 	if (!priv->irt_use_count)
636 		ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
637 
638 	priv->irt_use_count++;
639 }
640 
641 static void ipu_irt_disable(struct ipu_ic *ic)
642 {
643 	struct ipu_ic_priv *priv = ic->priv;
644 
645 	if (priv->irt_use_count) {
646 		if (!--priv->irt_use_count)
647 			ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
648 	}
649 }
650 
651 int ipu_ic_enable(struct ipu_ic *ic)
652 {
653 	struct ipu_ic_priv *priv = ic->priv;
654 	unsigned long flags;
655 
656 	spin_lock_irqsave(&priv->lock, flags);
657 
658 	if (!priv->use_count)
659 		ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
660 
661 	priv->use_count++;
662 
663 	if (ic->rotation)
664 		ipu_irt_enable(ic);
665 
666 	spin_unlock_irqrestore(&priv->lock, flags);
667 
668 	return 0;
669 }
670 EXPORT_SYMBOL_GPL(ipu_ic_enable);
671 
672 int ipu_ic_disable(struct ipu_ic *ic)
673 {
674 	struct ipu_ic_priv *priv = ic->priv;
675 	unsigned long flags;
676 
677 	spin_lock_irqsave(&priv->lock, flags);
678 
679 	priv->use_count--;
680 
681 	if (!priv->use_count)
682 		ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
683 
684 	if (priv->use_count < 0)
685 		priv->use_count = 0;
686 
687 	if (ic->rotation)
688 		ipu_irt_disable(ic);
689 
690 	ic->rotation = ic->graphics = false;
691 
692 	spin_unlock_irqrestore(&priv->lock, flags);
693 
694 	return 0;
695 }
696 EXPORT_SYMBOL_GPL(ipu_ic_disable);
697 
698 struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
699 {
700 	struct ipu_ic_priv *priv = ipu->ic_priv;
701 	unsigned long flags;
702 	struct ipu_ic *ic, *ret;
703 
704 	if (task >= IC_NUM_TASKS)
705 		return ERR_PTR(-EINVAL);
706 
707 	ic = &priv->task[task];
708 
709 	spin_lock_irqsave(&priv->lock, flags);
710 
711 	if (ic->in_use) {
712 		ret = ERR_PTR(-EBUSY);
713 		goto unlock;
714 	}
715 
716 	ic->in_use = true;
717 	ret = ic;
718 
719 unlock:
720 	spin_unlock_irqrestore(&priv->lock, flags);
721 	return ret;
722 }
723 EXPORT_SYMBOL_GPL(ipu_ic_get);
724 
725 void ipu_ic_put(struct ipu_ic *ic)
726 {
727 	struct ipu_ic_priv *priv = ic->priv;
728 	unsigned long flags;
729 
730 	spin_lock_irqsave(&priv->lock, flags);
731 	ic->in_use = false;
732 	spin_unlock_irqrestore(&priv->lock, flags);
733 }
734 EXPORT_SYMBOL_GPL(ipu_ic_put);
735 
736 int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
737 		unsigned long base, unsigned long tpmem_base)
738 {
739 	struct ipu_ic_priv *priv;
740 	int i;
741 
742 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
743 	if (!priv)
744 		return -ENOMEM;
745 
746 	ipu->ic_priv = priv;
747 
748 	spin_lock_init(&priv->lock);
749 	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
750 	if (!priv->base)
751 		return -ENOMEM;
752 	priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
753 	if (!priv->tpmem_base)
754 		return -ENOMEM;
755 
756 	dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
757 
758 	priv->ipu = ipu;
759 
760 	for (i = 0; i < IC_NUM_TASKS; i++) {
761 		priv->task[i].task = i;
762 		priv->task[i].priv = priv;
763 		priv->task[i].reg = &ic_task_reg[i];
764 		priv->task[i].bit = &ic_task_bit[i];
765 	}
766 
767 	return 0;
768 }
769 
770 void ipu_ic_exit(struct ipu_soc *ipu)
771 {
772 }
773 
774 void ipu_ic_dump(struct ipu_ic *ic)
775 {
776 	struct ipu_ic_priv *priv = ic->priv;
777 	struct ipu_soc *ipu = priv->ipu;
778 
779 	dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
780 		ipu_ic_read(ic, IC_CONF));
781 	dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
782 		ipu_ic_read(ic, IC_PRP_ENC_RSC));
783 	dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
784 		ipu_ic_read(ic, IC_PRP_VF_RSC));
785 	dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
786 		ipu_ic_read(ic, IC_PP_RSC));
787 	dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
788 		ipu_ic_read(ic, IC_CMBP_1));
789 	dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
790 		ipu_ic_read(ic, IC_CMBP_2));
791 	dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
792 		ipu_ic_read(ic, IC_IDMAC_1));
793 	dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
794 		ipu_ic_read(ic, IC_IDMAC_2));
795 	dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
796 		ipu_ic_read(ic, IC_IDMAC_3));
797 	dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
798 		ipu_ic_read(ic, IC_IDMAC_4));
799 }
800 EXPORT_SYMBOL_GPL(ipu_ic_dump);
801