xref: /openbmc/linux/drivers/gpu/ipu-v3/ipu-cpmem.c (revision 50df3be7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2012 Mentor Graphics Inc.
4  * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
5  */
6 #include <linux/types.h>
7 #include <linux/bitrev.h>
8 #include <linux/io.h>
9 #include <linux/sizes.h>
10 #include <drm/drm_fourcc.h>
11 #include "ipu-prv.h"
12 
13 struct ipu_cpmem_word {
14 	u32 data[5];
15 	u32 res[3];
16 };
17 
18 struct ipu_ch_param {
19 	struct ipu_cpmem_word word[2];
20 };
21 
22 struct ipu_cpmem {
23 	struct ipu_ch_param __iomem *base;
24 	u32 module;
25 	spinlock_t lock;
26 	int use_count;
27 	struct ipu_soc *ipu;
28 };
29 
30 #define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
31 
32 #define IPU_FIELD_UBO		IPU_CPMEM_WORD(0, 46, 22)
33 #define IPU_FIELD_VBO		IPU_CPMEM_WORD(0, 68, 22)
34 #define IPU_FIELD_IOX		IPU_CPMEM_WORD(0, 90, 4)
35 #define IPU_FIELD_RDRW		IPU_CPMEM_WORD(0, 94, 1)
36 #define IPU_FIELD_SO		IPU_CPMEM_WORD(0, 113, 1)
37 #define IPU_FIELD_SLY		IPU_CPMEM_WORD(1, 102, 14)
38 #define IPU_FIELD_SLUV		IPU_CPMEM_WORD(1, 128, 14)
39 
40 #define IPU_FIELD_XV		IPU_CPMEM_WORD(0, 0, 10)
41 #define IPU_FIELD_YV		IPU_CPMEM_WORD(0, 10, 9)
42 #define IPU_FIELD_XB		IPU_CPMEM_WORD(0, 19, 13)
43 #define IPU_FIELD_YB		IPU_CPMEM_WORD(0, 32, 12)
44 #define IPU_FIELD_NSB_B		IPU_CPMEM_WORD(0, 44, 1)
45 #define IPU_FIELD_CF		IPU_CPMEM_WORD(0, 45, 1)
46 #define IPU_FIELD_SX		IPU_CPMEM_WORD(0, 46, 12)
47 #define IPU_FIELD_SY		IPU_CPMEM_WORD(0, 58, 11)
48 #define IPU_FIELD_NS		IPU_CPMEM_WORD(0, 69, 10)
49 #define IPU_FIELD_SDX		IPU_CPMEM_WORD(0, 79, 7)
50 #define IPU_FIELD_SM		IPU_CPMEM_WORD(0, 86, 10)
51 #define IPU_FIELD_SCC		IPU_CPMEM_WORD(0, 96, 1)
52 #define IPU_FIELD_SCE		IPU_CPMEM_WORD(0, 97, 1)
53 #define IPU_FIELD_SDY		IPU_CPMEM_WORD(0, 98, 7)
54 #define IPU_FIELD_SDRX		IPU_CPMEM_WORD(0, 105, 1)
55 #define IPU_FIELD_SDRY		IPU_CPMEM_WORD(0, 106, 1)
56 #define IPU_FIELD_BPP		IPU_CPMEM_WORD(0, 107, 3)
57 #define IPU_FIELD_DEC_SEL	IPU_CPMEM_WORD(0, 110, 2)
58 #define IPU_FIELD_DIM		IPU_CPMEM_WORD(0, 112, 1)
59 #define IPU_FIELD_BNDM		IPU_CPMEM_WORD(0, 114, 3)
60 #define IPU_FIELD_BM		IPU_CPMEM_WORD(0, 117, 2)
61 #define IPU_FIELD_ROT		IPU_CPMEM_WORD(0, 119, 1)
62 #define IPU_FIELD_ROT_HF_VF	IPU_CPMEM_WORD(0, 119, 3)
63 #define IPU_FIELD_HF		IPU_CPMEM_WORD(0, 120, 1)
64 #define IPU_FIELD_VF		IPU_CPMEM_WORD(0, 121, 1)
65 #define IPU_FIELD_THE		IPU_CPMEM_WORD(0, 122, 1)
66 #define IPU_FIELD_CAP		IPU_CPMEM_WORD(0, 123, 1)
67 #define IPU_FIELD_CAE		IPU_CPMEM_WORD(0, 124, 1)
68 #define IPU_FIELD_FW		IPU_CPMEM_WORD(0, 125, 13)
69 #define IPU_FIELD_FH		IPU_CPMEM_WORD(0, 138, 12)
70 #define IPU_FIELD_EBA0		IPU_CPMEM_WORD(1, 0, 29)
71 #define IPU_FIELD_EBA1		IPU_CPMEM_WORD(1, 29, 29)
72 #define IPU_FIELD_ILO		IPU_CPMEM_WORD(1, 58, 20)
73 #define IPU_FIELD_NPB		IPU_CPMEM_WORD(1, 78, 7)
74 #define IPU_FIELD_PFS		IPU_CPMEM_WORD(1, 85, 4)
75 #define IPU_FIELD_ALU		IPU_CPMEM_WORD(1, 89, 1)
76 #define IPU_FIELD_ALBM		IPU_CPMEM_WORD(1, 90, 3)
77 #define IPU_FIELD_ID		IPU_CPMEM_WORD(1, 93, 2)
78 #define IPU_FIELD_TH		IPU_CPMEM_WORD(1, 95, 7)
79 #define IPU_FIELD_SL		IPU_CPMEM_WORD(1, 102, 14)
80 #define IPU_FIELD_WID0		IPU_CPMEM_WORD(1, 116, 3)
81 #define IPU_FIELD_WID1		IPU_CPMEM_WORD(1, 119, 3)
82 #define IPU_FIELD_WID2		IPU_CPMEM_WORD(1, 122, 3)
83 #define IPU_FIELD_WID3		IPU_CPMEM_WORD(1, 125, 3)
84 #define IPU_FIELD_OFS0		IPU_CPMEM_WORD(1, 128, 5)
85 #define IPU_FIELD_OFS1		IPU_CPMEM_WORD(1, 133, 5)
86 #define IPU_FIELD_OFS2		IPU_CPMEM_WORD(1, 138, 5)
87 #define IPU_FIELD_OFS3		IPU_CPMEM_WORD(1, 143, 5)
88 #define IPU_FIELD_SXYS		IPU_CPMEM_WORD(1, 148, 1)
89 #define IPU_FIELD_CRE		IPU_CPMEM_WORD(1, 149, 1)
90 #define IPU_FIELD_DEC_SEL2	IPU_CPMEM_WORD(1, 150, 1)
91 
92 static inline struct ipu_ch_param __iomem *
93 ipu_get_cpmem(struct ipuv3_channel *ch)
94 {
95 	struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
96 
97 	return cpmem->base + ch->num;
98 }
99 
100 static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
101 {
102 	struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
103 	u32 bit = (wbs >> 8) % 160;
104 	u32 size = wbs & 0xff;
105 	u32 word = (wbs >> 8) / 160;
106 	u32 i = bit / 32;
107 	u32 ofs = bit % 32;
108 	u32 mask = (1 << size) - 1;
109 	u32 val;
110 
111 	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
112 
113 	val = readl(&base->word[word].data[i]);
114 	val &= ~(mask << ofs);
115 	val |= v << ofs;
116 	writel(val, &base->word[word].data[i]);
117 
118 	if ((bit + size - 1) / 32 > i) {
119 		val = readl(&base->word[word].data[i + 1]);
120 		val &= ~(mask >> (ofs ? (32 - ofs) : 0));
121 		val |= v >> (ofs ? (32 - ofs) : 0);
122 		writel(val, &base->word[word].data[i + 1]);
123 	}
124 }
125 
126 static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
127 {
128 	struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
129 	u32 bit = (wbs >> 8) % 160;
130 	u32 size = wbs & 0xff;
131 	u32 word = (wbs >> 8) / 160;
132 	u32 i = bit / 32;
133 	u32 ofs = bit % 32;
134 	u32 mask = (1 << size) - 1;
135 	u32 val = 0;
136 
137 	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
138 
139 	val = (readl(&base->word[word].data[i]) >> ofs) & mask;
140 
141 	if ((bit + size - 1) / 32 > i) {
142 		u32 tmp;
143 
144 		tmp = readl(&base->word[word].data[i + 1]);
145 		tmp &= mask >> (ofs ? (32 - ofs) : 0);
146 		val |= tmp << (ofs ? (32 - ofs) : 0);
147 	}
148 
149 	return val;
150 }
151 
152 /*
153  * The V4L2 spec defines packed RGB formats in memory byte order, which from
154  * point of view of the IPU corresponds to little-endian words with the first
155  * component in the least significant bits.
156  * The DRM pixel formats and IPU internal representation are ordered the other
157  * way around, with the first named component ordered at the most significant
158  * bits. Further, V4L2 formats are not well defined:
159  *     https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
160  * We choose the interpretation which matches GStreamer behavior.
161  */
162 static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
163 {
164 	switch (pixelformat) {
165 	case V4L2_PIX_FMT_RGB565:
166 		/*
167 		 * Here we choose the 'corrected' interpretation of RGBP, a
168 		 * little-endian 16-bit word with the red component at the most
169 		 * significant bits:
170 		 * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
171 		 */
172 		return DRM_FORMAT_RGB565;
173 	case V4L2_PIX_FMT_BGR24:
174 		/* B G R <=> [24:0] R:G:B */
175 		return DRM_FORMAT_RGB888;
176 	case V4L2_PIX_FMT_RGB24:
177 		/* R G B <=> [24:0] B:G:R */
178 		return DRM_FORMAT_BGR888;
179 	case V4L2_PIX_FMT_BGR32:
180 		/* B G R A <=> [32:0] A:B:G:R */
181 		return DRM_FORMAT_XRGB8888;
182 	case V4L2_PIX_FMT_RGB32:
183 		/* R G B A <=> [32:0] A:B:G:R */
184 		return DRM_FORMAT_XBGR8888;
185 	case V4L2_PIX_FMT_ABGR32:
186 		/* B G R A <=> [32:0] A:R:G:B */
187 		return DRM_FORMAT_ARGB8888;
188 	case V4L2_PIX_FMT_XBGR32:
189 		/* B G R X <=> [32:0] X:R:G:B */
190 		return DRM_FORMAT_XRGB8888;
191 	case V4L2_PIX_FMT_BGRA32:
192 		/* A B G R <=> [32:0] R:G:B:A */
193 		return DRM_FORMAT_RGBA8888;
194 	case V4L2_PIX_FMT_BGRX32:
195 		/* X B G R <=> [32:0] R:G:B:X */
196 		return DRM_FORMAT_RGBX8888;
197 	case V4L2_PIX_FMT_RGBA32:
198 		/* R G B A <=> [32:0] A:B:G:R */
199 		return DRM_FORMAT_ABGR8888;
200 	case V4L2_PIX_FMT_RGBX32:
201 		/* R G B X <=> [32:0] X:B:G:R */
202 		return DRM_FORMAT_XBGR8888;
203 	case V4L2_PIX_FMT_ARGB32:
204 		/* A R G B <=> [32:0] B:G:R:A */
205 		return DRM_FORMAT_BGRA8888;
206 	case V4L2_PIX_FMT_XRGB32:
207 		/* X R G B <=> [32:0] B:G:R:X */
208 		return DRM_FORMAT_BGRX8888;
209 	case V4L2_PIX_FMT_UYVY:
210 		return DRM_FORMAT_UYVY;
211 	case V4L2_PIX_FMT_YUYV:
212 		return DRM_FORMAT_YUYV;
213 	case V4L2_PIX_FMT_YUV420:
214 		return DRM_FORMAT_YUV420;
215 	case V4L2_PIX_FMT_YUV422P:
216 		return DRM_FORMAT_YUV422;
217 	case V4L2_PIX_FMT_YVU420:
218 		return DRM_FORMAT_YVU420;
219 	case V4L2_PIX_FMT_NV12:
220 		return DRM_FORMAT_NV12;
221 	case V4L2_PIX_FMT_NV16:
222 		return DRM_FORMAT_NV16;
223 	}
224 
225 	return -EINVAL;
226 }
227 
228 void ipu_cpmem_zero(struct ipuv3_channel *ch)
229 {
230 	struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
231 	void __iomem *base = p;
232 	int i;
233 
234 	for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
235 		writel(0, base + i * sizeof(u32));
236 }
237 EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
238 
239 void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
240 {
241 	ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
242 	ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
243 }
244 EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
245 
246 void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
247 {
248 	ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
249 }
250 EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
251 
252 void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
253 {
254 	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
255 }
256 EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
257 
258 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
259 {
260 	struct ipu_soc *ipu = ch->ipu;
261 	u32 val;
262 
263 	if (ipu->ipu_type == IPUV3EX)
264 		ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
265 
266 	val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
267 	val |= 1 << (ch->num % 32);
268 	ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
269 };
270 EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
271 
272 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
273 {
274 	WARN_ON_ONCE(buf & 0x7);
275 
276 	if (bufnum)
277 		ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
278 	else
279 		ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
280 }
281 EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
282 
283 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
284 {
285 	WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
286 
287 	ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
288 	ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
289 }
290 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
291 
292 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
293 			       u32 pixelformat)
294 {
295 	u32 ilo, sly, sluv;
296 
297 	if (stride < 0) {
298 		stride = -stride;
299 		ilo = 0x100000 - (stride / 8);
300 	} else {
301 		ilo = stride / 8;
302 	}
303 
304 	sly = (stride * 2) - 1;
305 
306 	switch (pixelformat) {
307 	case V4L2_PIX_FMT_YUV420:
308 	case V4L2_PIX_FMT_YVU420:
309 		sluv = stride / 2 - 1;
310 		break;
311 	case V4L2_PIX_FMT_NV12:
312 		sluv = stride - 1;
313 		break;
314 	case V4L2_PIX_FMT_YUV422P:
315 		sluv = stride - 1;
316 		break;
317 	case V4L2_PIX_FMT_NV16:
318 		sluv = stride * 2 - 1;
319 		break;
320 	default:
321 		sluv = 0;
322 		break;
323 	}
324 
325 	ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
326 	ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
327 	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
328 	if (sluv)
329 		ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
330 };
331 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
332 
333 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
334 {
335 	id &= 0x3;
336 	ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
337 }
338 EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
339 
340 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
341 {
342 	return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
343 }
344 EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
345 
346 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
347 {
348 	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
349 };
350 EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
351 
352 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
353 {
354 	ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
355 }
356 EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
357 
358 void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
359 			    enum ipu_rotate_mode rot)
360 {
361 	u32 temp_rot = bitrev8(rot) >> 5;
362 
363 	ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
364 }
365 EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
366 
367 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
368 			     const struct ipu_rgb *rgb)
369 {
370 	int bpp = 0, npb = 0, ro, go, bo, to;
371 
372 	ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
373 	go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
374 	bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
375 	to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
376 
377 	ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
378 	ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
379 	ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
380 	ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
381 	ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
382 	ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
383 
384 	if (rgb->transp.length) {
385 		ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
386 				rgb->transp.length - 1);
387 		ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
388 	} else {
389 		ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
390 		ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
391 				rgb->bits_per_pixel);
392 	}
393 
394 	switch (rgb->bits_per_pixel) {
395 	case 32:
396 		bpp = 0;
397 		npb = 15;
398 		break;
399 	case 24:
400 		bpp = 1;
401 		npb = 19;
402 		break;
403 	case 16:
404 		bpp = 3;
405 		npb = 31;
406 		break;
407 	case 8:
408 		bpp = 5;
409 		npb = 63;
410 		break;
411 	default:
412 		return -EINVAL;
413 	}
414 	ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
415 	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
416 	ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
417 
418 	return 0;
419 }
420 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
421 
422 int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
423 {
424 	int bpp = 0, npb = 0;
425 
426 	switch (width) {
427 	case 32:
428 		bpp = 0;
429 		npb = 15;
430 		break;
431 	case 24:
432 		bpp = 1;
433 		npb = 19;
434 		break;
435 	case 16:
436 		bpp = 3;
437 		npb = 31;
438 		break;
439 	case 8:
440 		bpp = 5;
441 		npb = 63;
442 		break;
443 	default:
444 		return -EINVAL;
445 	}
446 
447 	ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
448 	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
449 	ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
450 
451 	return 0;
452 }
453 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
454 
455 void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
456 {
457 	switch (pixel_format) {
458 	case V4L2_PIX_FMT_UYVY:
459 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
460 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
461 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
462 		break;
463 	case V4L2_PIX_FMT_YUYV:
464 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
465 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
466 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
467 		break;
468 	}
469 }
470 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
471 
472 void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
473 				   unsigned int uv_stride,
474 				   unsigned int u_offset, unsigned int v_offset)
475 {
476 	WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
477 
478 	ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
479 	ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
480 	ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
481 }
482 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
483 
484 static const struct ipu_rgb def_xrgb_32 = {
485 	.red	= { .offset = 16, .length = 8, },
486 	.green	= { .offset =  8, .length = 8, },
487 	.blue	= { .offset =  0, .length = 8, },
488 	.transp = { .offset = 24, .length = 8, },
489 	.bits_per_pixel = 32,
490 };
491 
492 static const struct ipu_rgb def_xbgr_32 = {
493 	.red	= { .offset =  0, .length = 8, },
494 	.green	= { .offset =  8, .length = 8, },
495 	.blue	= { .offset = 16, .length = 8, },
496 	.transp = { .offset = 24, .length = 8, },
497 	.bits_per_pixel = 32,
498 };
499 
500 static const struct ipu_rgb def_rgbx_32 = {
501 	.red	= { .offset = 24, .length = 8, },
502 	.green	= { .offset = 16, .length = 8, },
503 	.blue	= { .offset =  8, .length = 8, },
504 	.transp = { .offset =  0, .length = 8, },
505 	.bits_per_pixel = 32,
506 };
507 
508 static const struct ipu_rgb def_bgrx_32 = {
509 	.red	= { .offset =  8, .length = 8, },
510 	.green	= { .offset = 16, .length = 8, },
511 	.blue	= { .offset = 24, .length = 8, },
512 	.transp = { .offset =  0, .length = 8, },
513 	.bits_per_pixel = 32,
514 };
515 
516 static const struct ipu_rgb def_rgb_24 = {
517 	.red	= { .offset = 16, .length = 8, },
518 	.green	= { .offset =  8, .length = 8, },
519 	.blue	= { .offset =  0, .length = 8, },
520 	.transp = { .offset =  0, .length = 0, },
521 	.bits_per_pixel = 24,
522 };
523 
524 static const struct ipu_rgb def_bgr_24 = {
525 	.red	= { .offset =  0, .length = 8, },
526 	.green	= { .offset =  8, .length = 8, },
527 	.blue	= { .offset = 16, .length = 8, },
528 	.transp = { .offset =  0, .length = 0, },
529 	.bits_per_pixel = 24,
530 };
531 
532 static const struct ipu_rgb def_rgb_16 = {
533 	.red	= { .offset = 11, .length = 5, },
534 	.green	= { .offset =  5, .length = 6, },
535 	.blue	= { .offset =  0, .length = 5, },
536 	.transp = { .offset =  0, .length = 0, },
537 	.bits_per_pixel = 16,
538 };
539 
540 static const struct ipu_rgb def_bgr_16 = {
541 	.red	= { .offset =  0, .length = 5, },
542 	.green	= { .offset =  5, .length = 6, },
543 	.blue	= { .offset = 11, .length = 5, },
544 	.transp = { .offset =  0, .length = 0, },
545 	.bits_per_pixel = 16,
546 };
547 
548 static const struct ipu_rgb def_argb_16 = {
549 	.red	= { .offset = 10, .length = 5, },
550 	.green	= { .offset =  5, .length = 5, },
551 	.blue	= { .offset =  0, .length = 5, },
552 	.transp = { .offset = 15, .length = 1, },
553 	.bits_per_pixel = 16,
554 };
555 
556 static const struct ipu_rgb def_argb_16_4444 = {
557 	.red	= { .offset =  8, .length = 4, },
558 	.green	= { .offset =  4, .length = 4, },
559 	.blue	= { .offset =  0, .length = 4, },
560 	.transp = { .offset = 12, .length = 4, },
561 	.bits_per_pixel = 16,
562 };
563 
564 static const struct ipu_rgb def_abgr_16 = {
565 	.red	= { .offset =  0, .length = 5, },
566 	.green	= { .offset =  5, .length = 5, },
567 	.blue	= { .offset = 10, .length = 5, },
568 	.transp = { .offset = 15, .length = 1, },
569 	.bits_per_pixel = 16,
570 };
571 
572 static const struct ipu_rgb def_rgba_16 = {
573 	.red	= { .offset = 11, .length = 5, },
574 	.green	= { .offset =  6, .length = 5, },
575 	.blue	= { .offset =  1, .length = 5, },
576 	.transp = { .offset =  0, .length = 1, },
577 	.bits_per_pixel = 16,
578 };
579 
580 static const struct ipu_rgb def_bgra_16 = {
581 	.red	= { .offset =  1, .length = 5, },
582 	.green	= { .offset =  6, .length = 5, },
583 	.blue	= { .offset = 11, .length = 5, },
584 	.transp = { .offset =  0, .length = 1, },
585 	.bits_per_pixel = 16,
586 };
587 
588 #define Y_OFFSET(pix, x, y)	((x) + pix->width * (y))
589 #define U_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
590 				 (pix->width * ((y) / 2) / 2) + (x) / 2)
591 #define V_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
592 				 (pix->width * pix->height / 4) +	\
593 				 (pix->width * ((y) / 2) / 2) + (x) / 2)
594 #define U2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
595 				 (pix->width * (y) / 2) + (x) / 2)
596 #define V2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
597 				 (pix->width * pix->height / 2) +	\
598 				 (pix->width * (y) / 2) + (x) / 2)
599 #define UV_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
600 				 (pix->width * ((y) / 2)) + (x))
601 #define UV2_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
602 				 (pix->width * y) + (x))
603 
604 #define NUM_ALPHA_CHANNELS	7
605 
606 /* See Table 37-12. Alpha channels mapping. */
607 static int ipu_channel_albm(int ch_num)
608 {
609 	switch (ch_num) {
610 	case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:	return 0;
611 	case IPUV3_CHANNEL_G_MEM_IC_PP:		return 1;
612 	case IPUV3_CHANNEL_MEM_FG_SYNC:		return 2;
613 	case IPUV3_CHANNEL_MEM_FG_ASYNC:	return 3;
614 	case IPUV3_CHANNEL_MEM_BG_SYNC:		return 4;
615 	case IPUV3_CHANNEL_MEM_BG_ASYNC:	return 5;
616 	case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
617 	default:
618 		return -EINVAL;
619 	}
620 }
621 
622 static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
623 {
624 	struct ipu_soc *ipu = ch->ipu;
625 	int albm;
626 	u32 val;
627 
628 	albm = ipu_channel_albm(ch->num);
629 	if (albm < 0)
630 		return;
631 
632 	ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
633 	ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
634 	ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
635 
636 	val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
637 	val |= BIT(ch->num);
638 	ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
639 }
640 
641 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
642 {
643 	switch (drm_fourcc) {
644 	case DRM_FORMAT_YUV420:
645 	case DRM_FORMAT_YVU420:
646 		/* pix format */
647 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
648 		/* burst size */
649 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
650 		break;
651 	case DRM_FORMAT_YUV422:
652 	case DRM_FORMAT_YVU422:
653 		/* pix format */
654 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
655 		/* burst size */
656 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
657 		break;
658 	case DRM_FORMAT_YUV444:
659 	case DRM_FORMAT_YVU444:
660 		/* pix format */
661 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
662 		/* burst size */
663 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
664 		break;
665 	case DRM_FORMAT_NV12:
666 		/* pix format */
667 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
668 		/* burst size */
669 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
670 		break;
671 	case DRM_FORMAT_NV16:
672 		/* pix format */
673 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
674 		/* burst size */
675 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
676 		break;
677 	case DRM_FORMAT_UYVY:
678 		/* bits/pixel */
679 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
680 		/* pix format */
681 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
682 		/* burst size */
683 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
684 		break;
685 	case DRM_FORMAT_YUYV:
686 		/* bits/pixel */
687 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
688 		/* pix format */
689 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
690 		/* burst size */
691 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
692 		break;
693 	case DRM_FORMAT_ABGR8888:
694 	case DRM_FORMAT_XBGR8888:
695 		ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
696 		break;
697 	case DRM_FORMAT_ARGB8888:
698 	case DRM_FORMAT_XRGB8888:
699 		ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
700 		break;
701 	case DRM_FORMAT_RGBA8888:
702 	case DRM_FORMAT_RGBX8888:
703 	case DRM_FORMAT_RGBX8888_A8:
704 		ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
705 		break;
706 	case DRM_FORMAT_BGRA8888:
707 	case DRM_FORMAT_BGRX8888:
708 	case DRM_FORMAT_BGRX8888_A8:
709 		ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
710 		break;
711 	case DRM_FORMAT_BGR888:
712 	case DRM_FORMAT_BGR888_A8:
713 		ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
714 		break;
715 	case DRM_FORMAT_RGB888:
716 	case DRM_FORMAT_RGB888_A8:
717 		ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
718 		break;
719 	case DRM_FORMAT_RGB565:
720 	case DRM_FORMAT_RGB565_A8:
721 		ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
722 		break;
723 	case DRM_FORMAT_BGR565:
724 	case DRM_FORMAT_BGR565_A8:
725 		ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
726 		break;
727 	case DRM_FORMAT_ARGB1555:
728 		ipu_cpmem_set_format_rgb(ch, &def_argb_16);
729 		break;
730 	case DRM_FORMAT_ABGR1555:
731 		ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
732 		break;
733 	case DRM_FORMAT_RGBA5551:
734 		ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
735 		break;
736 	case DRM_FORMAT_BGRA5551:
737 		ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
738 		break;
739 	case DRM_FORMAT_ARGB4444:
740 		ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
741 		break;
742 	default:
743 		return -EINVAL;
744 	}
745 
746 	switch (drm_fourcc) {
747 	case DRM_FORMAT_RGB565_A8:
748 	case DRM_FORMAT_BGR565_A8:
749 	case DRM_FORMAT_RGB888_A8:
750 	case DRM_FORMAT_BGR888_A8:
751 	case DRM_FORMAT_RGBX8888_A8:
752 	case DRM_FORMAT_BGRX8888_A8:
753 		ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
754 		ipu_cpmem_set_separate_alpha(ch);
755 		break;
756 	default:
757 		break;
758 	}
759 
760 	return 0;
761 }
762 EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
763 
764 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
765 {
766 	struct v4l2_pix_format *pix = &image->pix;
767 	int offset, u_offset, v_offset;
768 	int ret = 0;
769 
770 	pr_debug("%s: resolution: %dx%d stride: %d\n",
771 		 __func__, pix->width, pix->height,
772 		 pix->bytesperline);
773 
774 	ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
775 	ipu_cpmem_set_stride(ch, pix->bytesperline);
776 
777 	ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
778 
779 	switch (pix->pixelformat) {
780 	case V4L2_PIX_FMT_YUV420:
781 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
782 		u_offset = image->u_offset ?
783 			image->u_offset : U_OFFSET(pix, image->rect.left,
784 						   image->rect.top) - offset;
785 		v_offset = image->v_offset ?
786 			image->v_offset : V_OFFSET(pix, image->rect.left,
787 						   image->rect.top) - offset;
788 
789 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
790 					      u_offset, v_offset);
791 		break;
792 	case V4L2_PIX_FMT_YVU420:
793 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
794 		u_offset = image->u_offset ?
795 			image->u_offset : V_OFFSET(pix, image->rect.left,
796 						   image->rect.top) - offset;
797 		v_offset = image->v_offset ?
798 			image->v_offset : U_OFFSET(pix, image->rect.left,
799 						   image->rect.top) - offset;
800 
801 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
802 					      u_offset, v_offset);
803 		break;
804 	case V4L2_PIX_FMT_YUV422P:
805 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
806 		u_offset = image->u_offset ?
807 			image->u_offset : U2_OFFSET(pix, image->rect.left,
808 						    image->rect.top) - offset;
809 		v_offset = image->v_offset ?
810 			image->v_offset : V2_OFFSET(pix, image->rect.left,
811 						    image->rect.top) - offset;
812 
813 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
814 					      u_offset, v_offset);
815 		break;
816 	case V4L2_PIX_FMT_NV12:
817 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
818 		u_offset = image->u_offset ?
819 			image->u_offset : UV_OFFSET(pix, image->rect.left,
820 						    image->rect.top) - offset;
821 		v_offset = image->v_offset ? image->v_offset : 0;
822 
823 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
824 					      u_offset, v_offset);
825 		break;
826 	case V4L2_PIX_FMT_NV16:
827 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
828 		u_offset = image->u_offset ?
829 			image->u_offset : UV2_OFFSET(pix, image->rect.left,
830 						     image->rect.top) - offset;
831 		v_offset = image->v_offset ? image->v_offset : 0;
832 
833 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
834 					      u_offset, v_offset);
835 		break;
836 	case V4L2_PIX_FMT_UYVY:
837 	case V4L2_PIX_FMT_YUYV:
838 	case V4L2_PIX_FMT_RGB565:
839 		offset = image->rect.left * 2 +
840 			image->rect.top * pix->bytesperline;
841 		break;
842 	case V4L2_PIX_FMT_RGB32:
843 	case V4L2_PIX_FMT_BGR32:
844 	case V4L2_PIX_FMT_ABGR32:
845 	case V4L2_PIX_FMT_XBGR32:
846 	case V4L2_PIX_FMT_BGRA32:
847 	case V4L2_PIX_FMT_BGRX32:
848 	case V4L2_PIX_FMT_RGBA32:
849 	case V4L2_PIX_FMT_RGBX32:
850 	case V4L2_PIX_FMT_ARGB32:
851 	case V4L2_PIX_FMT_XRGB32:
852 		offset = image->rect.left * 4 +
853 			image->rect.top * pix->bytesperline;
854 		break;
855 	case V4L2_PIX_FMT_RGB24:
856 	case V4L2_PIX_FMT_BGR24:
857 		offset = image->rect.left * 3 +
858 			image->rect.top * pix->bytesperline;
859 		break;
860 	case V4L2_PIX_FMT_SBGGR8:
861 	case V4L2_PIX_FMT_SGBRG8:
862 	case V4L2_PIX_FMT_SGRBG8:
863 	case V4L2_PIX_FMT_SRGGB8:
864 	case V4L2_PIX_FMT_GREY:
865 		offset = image->rect.left + image->rect.top * pix->bytesperline;
866 		break;
867 	case V4L2_PIX_FMT_SBGGR16:
868 	case V4L2_PIX_FMT_SGBRG16:
869 	case V4L2_PIX_FMT_SGRBG16:
870 	case V4L2_PIX_FMT_SRGGB16:
871 	case V4L2_PIX_FMT_Y16:
872 		offset = image->rect.left * 2 +
873 			 image->rect.top * pix->bytesperline;
874 		break;
875 	default:
876 		/* This should not happen */
877 		WARN_ON(1);
878 		offset = 0;
879 		ret = -EINVAL;
880 	}
881 
882 	ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
883 	ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
884 
885 	return ret;
886 }
887 EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
888 
889 void ipu_cpmem_dump(struct ipuv3_channel *ch)
890 {
891 	struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
892 	struct ipu_soc *ipu = ch->ipu;
893 	int chno = ch->num;
894 
895 	dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
896 		readl(&p->word[0].data[0]),
897 		readl(&p->word[0].data[1]),
898 		readl(&p->word[0].data[2]),
899 		readl(&p->word[0].data[3]),
900 		readl(&p->word[0].data[4]));
901 	dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
902 		readl(&p->word[1].data[0]),
903 		readl(&p->word[1].data[1]),
904 		readl(&p->word[1].data[2]),
905 		readl(&p->word[1].data[3]),
906 		readl(&p->word[1].data[4]));
907 	dev_dbg(ipu->dev, "PFS 0x%x, ",
908 		 ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
909 	dev_dbg(ipu->dev, "BPP 0x%x, ",
910 		ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
911 	dev_dbg(ipu->dev, "NPB 0x%x\n",
912 		 ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
913 
914 	dev_dbg(ipu->dev, "FW %d, ",
915 		 ipu_ch_param_read_field(ch, IPU_FIELD_FW));
916 	dev_dbg(ipu->dev, "FH %d, ",
917 		 ipu_ch_param_read_field(ch, IPU_FIELD_FH));
918 	dev_dbg(ipu->dev, "EBA0 0x%x\n",
919 		 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
920 	dev_dbg(ipu->dev, "EBA1 0x%x\n",
921 		 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
922 	dev_dbg(ipu->dev, "Stride %d\n",
923 		 ipu_ch_param_read_field(ch, IPU_FIELD_SL));
924 	dev_dbg(ipu->dev, "scan_order %d\n",
925 		 ipu_ch_param_read_field(ch, IPU_FIELD_SO));
926 	dev_dbg(ipu->dev, "uv_stride %d\n",
927 		 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
928 	dev_dbg(ipu->dev, "u_offset 0x%x\n",
929 		 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
930 	dev_dbg(ipu->dev, "v_offset 0x%x\n",
931 		 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
932 
933 	dev_dbg(ipu->dev, "Width0 %d+1, ",
934 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
935 	dev_dbg(ipu->dev, "Width1 %d+1, ",
936 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
937 	dev_dbg(ipu->dev, "Width2 %d+1, ",
938 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
939 	dev_dbg(ipu->dev, "Width3 %d+1, ",
940 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
941 	dev_dbg(ipu->dev, "Offset0 %d, ",
942 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
943 	dev_dbg(ipu->dev, "Offset1 %d, ",
944 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
945 	dev_dbg(ipu->dev, "Offset2 %d, ",
946 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
947 	dev_dbg(ipu->dev, "Offset3 %d\n",
948 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
949 }
950 EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
951 
952 int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
953 {
954 	struct ipu_cpmem *cpmem;
955 
956 	cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
957 	if (!cpmem)
958 		return -ENOMEM;
959 
960 	ipu->cpmem_priv = cpmem;
961 
962 	spin_lock_init(&cpmem->lock);
963 	cpmem->base = devm_ioremap(dev, base, SZ_128K);
964 	if (!cpmem->base)
965 		return -ENOMEM;
966 
967 	dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
968 		base, cpmem->base);
969 	cpmem->ipu = ipu;
970 
971 	return 0;
972 }
973 
974 void ipu_cpmem_exit(struct ipu_soc *ipu)
975 {
976 }
977