xref: /openbmc/linux/drivers/gpu/ipu-v3/ipu-cpmem.c (revision 22d55f02)
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_XBGR32:
186 		/* B G R X <=> [32:0] X:R:G:B */
187 		return DRM_FORMAT_XRGB8888;
188 	case V4L2_PIX_FMT_XRGB32:
189 		/* X R G B <=> [32:0] B:G:R:X */
190 		return DRM_FORMAT_BGRX8888;
191 	case V4L2_PIX_FMT_UYVY:
192 		return DRM_FORMAT_UYVY;
193 	case V4L2_PIX_FMT_YUYV:
194 		return DRM_FORMAT_YUYV;
195 	case V4L2_PIX_FMT_YUV420:
196 		return DRM_FORMAT_YUV420;
197 	case V4L2_PIX_FMT_YUV422P:
198 		return DRM_FORMAT_YUV422;
199 	case V4L2_PIX_FMT_YVU420:
200 		return DRM_FORMAT_YVU420;
201 	case V4L2_PIX_FMT_NV12:
202 		return DRM_FORMAT_NV12;
203 	case V4L2_PIX_FMT_NV16:
204 		return DRM_FORMAT_NV16;
205 	}
206 
207 	return -EINVAL;
208 }
209 
210 void ipu_cpmem_zero(struct ipuv3_channel *ch)
211 {
212 	struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
213 	void __iomem *base = p;
214 	int i;
215 
216 	for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
217 		writel(0, base + i * sizeof(u32));
218 }
219 EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
220 
221 void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
222 {
223 	ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
224 	ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
225 }
226 EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
227 
228 void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
229 {
230 	ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
231 }
232 EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
233 
234 void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
235 {
236 	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
237 }
238 EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
239 
240 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
241 {
242 	struct ipu_soc *ipu = ch->ipu;
243 	u32 val;
244 
245 	if (ipu->ipu_type == IPUV3EX)
246 		ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
247 
248 	val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
249 	val |= 1 << (ch->num % 32);
250 	ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
251 };
252 EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
253 
254 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
255 {
256 	WARN_ON_ONCE(buf & 0x7);
257 
258 	if (bufnum)
259 		ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
260 	else
261 		ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
262 }
263 EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
264 
265 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
266 {
267 	WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
268 
269 	ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
270 	ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
271 }
272 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
273 
274 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
275 			       u32 pixelformat)
276 {
277 	u32 ilo, sly, sluv;
278 
279 	if (stride < 0) {
280 		stride = -stride;
281 		ilo = 0x100000 - (stride / 8);
282 	} else {
283 		ilo = stride / 8;
284 	}
285 
286 	sly = (stride * 2) - 1;
287 
288 	switch (pixelformat) {
289 	case V4L2_PIX_FMT_YUV420:
290 	case V4L2_PIX_FMT_YVU420:
291 		sluv = stride / 2 - 1;
292 		break;
293 	case V4L2_PIX_FMT_NV12:
294 		sluv = stride - 1;
295 		break;
296 	case V4L2_PIX_FMT_YUV422P:
297 		sluv = stride - 1;
298 		break;
299 	case V4L2_PIX_FMT_NV16:
300 		sluv = stride * 2 - 1;
301 		break;
302 	default:
303 		sluv = 0;
304 		break;
305 	}
306 
307 	ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
308 	ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
309 	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
310 	if (sluv)
311 		ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
312 };
313 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
314 
315 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
316 {
317 	id &= 0x3;
318 	ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
319 }
320 EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
321 
322 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
323 {
324 	return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
325 }
326 EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
327 
328 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
329 {
330 	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
331 };
332 EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
333 
334 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
335 {
336 	ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
337 }
338 EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
339 
340 void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
341 			    enum ipu_rotate_mode rot)
342 {
343 	u32 temp_rot = bitrev8(rot) >> 5;
344 
345 	ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
346 }
347 EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
348 
349 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
350 			     const struct ipu_rgb *rgb)
351 {
352 	int bpp = 0, npb = 0, ro, go, bo, to;
353 
354 	ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
355 	go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
356 	bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
357 	to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
358 
359 	ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
360 	ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
361 	ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
362 	ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
363 	ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
364 	ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
365 
366 	if (rgb->transp.length) {
367 		ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
368 				rgb->transp.length - 1);
369 		ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
370 	} else {
371 		ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
372 		ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
373 				rgb->bits_per_pixel);
374 	}
375 
376 	switch (rgb->bits_per_pixel) {
377 	case 32:
378 		bpp = 0;
379 		npb = 15;
380 		break;
381 	case 24:
382 		bpp = 1;
383 		npb = 19;
384 		break;
385 	case 16:
386 		bpp = 3;
387 		npb = 31;
388 		break;
389 	case 8:
390 		bpp = 5;
391 		npb = 63;
392 		break;
393 	default:
394 		return -EINVAL;
395 	}
396 	ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
397 	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
398 	ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
399 
400 	return 0;
401 }
402 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
403 
404 int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
405 {
406 	int bpp = 0, npb = 0;
407 
408 	switch (width) {
409 	case 32:
410 		bpp = 0;
411 		npb = 15;
412 		break;
413 	case 24:
414 		bpp = 1;
415 		npb = 19;
416 		break;
417 	case 16:
418 		bpp = 3;
419 		npb = 31;
420 		break;
421 	case 8:
422 		bpp = 5;
423 		npb = 63;
424 		break;
425 	default:
426 		return -EINVAL;
427 	}
428 
429 	ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
430 	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
431 	ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
432 
433 	return 0;
434 }
435 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
436 
437 void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
438 {
439 	switch (pixel_format) {
440 	case V4L2_PIX_FMT_UYVY:
441 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
442 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
443 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
444 		break;
445 	case V4L2_PIX_FMT_YUYV:
446 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
447 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
448 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
449 		break;
450 	}
451 }
452 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
453 
454 void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
455 				   unsigned int uv_stride,
456 				   unsigned int u_offset, unsigned int v_offset)
457 {
458 	WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
459 
460 	ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
461 	ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
462 	ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
463 }
464 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
465 
466 static const struct ipu_rgb def_xrgb_32 = {
467 	.red	= { .offset = 16, .length = 8, },
468 	.green	= { .offset =  8, .length = 8, },
469 	.blue	= { .offset =  0, .length = 8, },
470 	.transp = { .offset = 24, .length = 8, },
471 	.bits_per_pixel = 32,
472 };
473 
474 static const struct ipu_rgb def_xbgr_32 = {
475 	.red	= { .offset =  0, .length = 8, },
476 	.green	= { .offset =  8, .length = 8, },
477 	.blue	= { .offset = 16, .length = 8, },
478 	.transp = { .offset = 24, .length = 8, },
479 	.bits_per_pixel = 32,
480 };
481 
482 static const struct ipu_rgb def_rgbx_32 = {
483 	.red	= { .offset = 24, .length = 8, },
484 	.green	= { .offset = 16, .length = 8, },
485 	.blue	= { .offset =  8, .length = 8, },
486 	.transp = { .offset =  0, .length = 8, },
487 	.bits_per_pixel = 32,
488 };
489 
490 static const struct ipu_rgb def_bgrx_32 = {
491 	.red	= { .offset =  8, .length = 8, },
492 	.green	= { .offset = 16, .length = 8, },
493 	.blue	= { .offset = 24, .length = 8, },
494 	.transp = { .offset =  0, .length = 8, },
495 	.bits_per_pixel = 32,
496 };
497 
498 static const struct ipu_rgb def_rgb_24 = {
499 	.red	= { .offset = 16, .length = 8, },
500 	.green	= { .offset =  8, .length = 8, },
501 	.blue	= { .offset =  0, .length = 8, },
502 	.transp = { .offset =  0, .length = 0, },
503 	.bits_per_pixel = 24,
504 };
505 
506 static const struct ipu_rgb def_bgr_24 = {
507 	.red	= { .offset =  0, .length = 8, },
508 	.green	= { .offset =  8, .length = 8, },
509 	.blue	= { .offset = 16, .length = 8, },
510 	.transp = { .offset =  0, .length = 0, },
511 	.bits_per_pixel = 24,
512 };
513 
514 static const struct ipu_rgb def_rgb_16 = {
515 	.red	= { .offset = 11, .length = 5, },
516 	.green	= { .offset =  5, .length = 6, },
517 	.blue	= { .offset =  0, .length = 5, },
518 	.transp = { .offset =  0, .length = 0, },
519 	.bits_per_pixel = 16,
520 };
521 
522 static const struct ipu_rgb def_bgr_16 = {
523 	.red	= { .offset =  0, .length = 5, },
524 	.green	= { .offset =  5, .length = 6, },
525 	.blue	= { .offset = 11, .length = 5, },
526 	.transp = { .offset =  0, .length = 0, },
527 	.bits_per_pixel = 16,
528 };
529 
530 static const struct ipu_rgb def_argb_16 = {
531 	.red	= { .offset = 10, .length = 5, },
532 	.green	= { .offset =  5, .length = 5, },
533 	.blue	= { .offset =  0, .length = 5, },
534 	.transp = { .offset = 15, .length = 1, },
535 	.bits_per_pixel = 16,
536 };
537 
538 static const struct ipu_rgb def_argb_16_4444 = {
539 	.red	= { .offset =  8, .length = 4, },
540 	.green	= { .offset =  4, .length = 4, },
541 	.blue	= { .offset =  0, .length = 4, },
542 	.transp = { .offset = 12, .length = 4, },
543 	.bits_per_pixel = 16,
544 };
545 
546 static const struct ipu_rgb def_abgr_16 = {
547 	.red	= { .offset =  0, .length = 5, },
548 	.green	= { .offset =  5, .length = 5, },
549 	.blue	= { .offset = 10, .length = 5, },
550 	.transp = { .offset = 15, .length = 1, },
551 	.bits_per_pixel = 16,
552 };
553 
554 static const struct ipu_rgb def_rgba_16 = {
555 	.red	= { .offset = 11, .length = 5, },
556 	.green	= { .offset =  6, .length = 5, },
557 	.blue	= { .offset =  1, .length = 5, },
558 	.transp = { .offset =  0, .length = 1, },
559 	.bits_per_pixel = 16,
560 };
561 
562 static const struct ipu_rgb def_bgra_16 = {
563 	.red	= { .offset =  1, .length = 5, },
564 	.green	= { .offset =  6, .length = 5, },
565 	.blue	= { .offset = 11, .length = 5, },
566 	.transp = { .offset =  0, .length = 1, },
567 	.bits_per_pixel = 16,
568 };
569 
570 #define Y_OFFSET(pix, x, y)	((x) + pix->width * (y))
571 #define U_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
572 				 (pix->width * ((y) / 2) / 2) + (x) / 2)
573 #define V_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
574 				 (pix->width * pix->height / 4) +	\
575 				 (pix->width * ((y) / 2) / 2) + (x) / 2)
576 #define U2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
577 				 (pix->width * (y) / 2) + (x) / 2)
578 #define V2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
579 				 (pix->width * pix->height / 2) +	\
580 				 (pix->width * (y) / 2) + (x) / 2)
581 #define UV_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
582 				 (pix->width * ((y) / 2)) + (x))
583 #define UV2_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
584 				 (pix->width * y) + (x))
585 
586 #define NUM_ALPHA_CHANNELS	7
587 
588 /* See Table 37-12. Alpha channels mapping. */
589 static int ipu_channel_albm(int ch_num)
590 {
591 	switch (ch_num) {
592 	case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:	return 0;
593 	case IPUV3_CHANNEL_G_MEM_IC_PP:		return 1;
594 	case IPUV3_CHANNEL_MEM_FG_SYNC:		return 2;
595 	case IPUV3_CHANNEL_MEM_FG_ASYNC:	return 3;
596 	case IPUV3_CHANNEL_MEM_BG_SYNC:		return 4;
597 	case IPUV3_CHANNEL_MEM_BG_ASYNC:	return 5;
598 	case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
599 	default:
600 		return -EINVAL;
601 	}
602 }
603 
604 static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
605 {
606 	struct ipu_soc *ipu = ch->ipu;
607 	int albm;
608 	u32 val;
609 
610 	albm = ipu_channel_albm(ch->num);
611 	if (albm < 0)
612 		return;
613 
614 	ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
615 	ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
616 	ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
617 
618 	val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
619 	val |= BIT(ch->num);
620 	ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
621 }
622 
623 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
624 {
625 	switch (drm_fourcc) {
626 	case DRM_FORMAT_YUV420:
627 	case DRM_FORMAT_YVU420:
628 		/* pix format */
629 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
630 		/* burst size */
631 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
632 		break;
633 	case DRM_FORMAT_YUV422:
634 	case DRM_FORMAT_YVU422:
635 		/* pix format */
636 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
637 		/* burst size */
638 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
639 		break;
640 	case DRM_FORMAT_YUV444:
641 	case DRM_FORMAT_YVU444:
642 		/* pix format */
643 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
644 		/* burst size */
645 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
646 		break;
647 	case DRM_FORMAT_NV12:
648 		/* pix format */
649 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
650 		/* burst size */
651 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
652 		break;
653 	case DRM_FORMAT_NV16:
654 		/* pix format */
655 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
656 		/* burst size */
657 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
658 		break;
659 	case DRM_FORMAT_UYVY:
660 		/* bits/pixel */
661 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
662 		/* pix format */
663 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
664 		/* burst size */
665 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
666 		break;
667 	case DRM_FORMAT_YUYV:
668 		/* bits/pixel */
669 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
670 		/* pix format */
671 		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
672 		/* burst size */
673 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
674 		break;
675 	case DRM_FORMAT_ABGR8888:
676 	case DRM_FORMAT_XBGR8888:
677 		ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
678 		break;
679 	case DRM_FORMAT_ARGB8888:
680 	case DRM_FORMAT_XRGB8888:
681 		ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
682 		break;
683 	case DRM_FORMAT_RGBA8888:
684 	case DRM_FORMAT_RGBX8888:
685 	case DRM_FORMAT_RGBX8888_A8:
686 		ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
687 		break;
688 	case DRM_FORMAT_BGRA8888:
689 	case DRM_FORMAT_BGRX8888:
690 	case DRM_FORMAT_BGRX8888_A8:
691 		ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
692 		break;
693 	case DRM_FORMAT_BGR888:
694 	case DRM_FORMAT_BGR888_A8:
695 		ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
696 		break;
697 	case DRM_FORMAT_RGB888:
698 	case DRM_FORMAT_RGB888_A8:
699 		ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
700 		break;
701 	case DRM_FORMAT_RGB565:
702 	case DRM_FORMAT_RGB565_A8:
703 		ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
704 		break;
705 	case DRM_FORMAT_BGR565:
706 	case DRM_FORMAT_BGR565_A8:
707 		ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
708 		break;
709 	case DRM_FORMAT_ARGB1555:
710 		ipu_cpmem_set_format_rgb(ch, &def_argb_16);
711 		break;
712 	case DRM_FORMAT_ABGR1555:
713 		ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
714 		break;
715 	case DRM_FORMAT_RGBA5551:
716 		ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
717 		break;
718 	case DRM_FORMAT_BGRA5551:
719 		ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
720 		break;
721 	case DRM_FORMAT_ARGB4444:
722 		ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
723 		break;
724 	default:
725 		return -EINVAL;
726 	}
727 
728 	switch (drm_fourcc) {
729 	case DRM_FORMAT_RGB565_A8:
730 	case DRM_FORMAT_BGR565_A8:
731 	case DRM_FORMAT_RGB888_A8:
732 	case DRM_FORMAT_BGR888_A8:
733 	case DRM_FORMAT_RGBX8888_A8:
734 	case DRM_FORMAT_BGRX8888_A8:
735 		ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
736 		ipu_cpmem_set_separate_alpha(ch);
737 		break;
738 	default:
739 		break;
740 	}
741 
742 	return 0;
743 }
744 EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
745 
746 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
747 {
748 	struct v4l2_pix_format *pix = &image->pix;
749 	int offset, u_offset, v_offset;
750 	int ret = 0;
751 
752 	pr_debug("%s: resolution: %dx%d stride: %d\n",
753 		 __func__, pix->width, pix->height,
754 		 pix->bytesperline);
755 
756 	ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
757 	ipu_cpmem_set_stride(ch, pix->bytesperline);
758 
759 	ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
760 
761 	switch (pix->pixelformat) {
762 	case V4L2_PIX_FMT_YUV420:
763 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
764 		u_offset = image->u_offset ?
765 			image->u_offset : U_OFFSET(pix, image->rect.left,
766 						   image->rect.top) - offset;
767 		v_offset = image->v_offset ?
768 			image->v_offset : V_OFFSET(pix, image->rect.left,
769 						   image->rect.top) - offset;
770 
771 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
772 					      u_offset, v_offset);
773 		break;
774 	case V4L2_PIX_FMT_YVU420:
775 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
776 		u_offset = image->u_offset ?
777 			image->u_offset : V_OFFSET(pix, image->rect.left,
778 						   image->rect.top) - offset;
779 		v_offset = image->v_offset ?
780 			image->v_offset : U_OFFSET(pix, image->rect.left,
781 						   image->rect.top) - offset;
782 
783 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
784 					      u_offset, v_offset);
785 		break;
786 	case V4L2_PIX_FMT_YUV422P:
787 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
788 		u_offset = image->u_offset ?
789 			image->u_offset : U2_OFFSET(pix, image->rect.left,
790 						    image->rect.top) - offset;
791 		v_offset = image->v_offset ?
792 			image->v_offset : V2_OFFSET(pix, image->rect.left,
793 						    image->rect.top) - offset;
794 
795 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
796 					      u_offset, v_offset);
797 		break;
798 	case V4L2_PIX_FMT_NV12:
799 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
800 		u_offset = image->u_offset ?
801 			image->u_offset : UV_OFFSET(pix, image->rect.left,
802 						    image->rect.top) - offset;
803 		v_offset = image->v_offset ? image->v_offset : 0;
804 
805 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
806 					      u_offset, v_offset);
807 		break;
808 	case V4L2_PIX_FMT_NV16:
809 		offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
810 		u_offset = image->u_offset ?
811 			image->u_offset : UV2_OFFSET(pix, image->rect.left,
812 						     image->rect.top) - offset;
813 		v_offset = image->v_offset ? image->v_offset : 0;
814 
815 		ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
816 					      u_offset, v_offset);
817 		break;
818 	case V4L2_PIX_FMT_UYVY:
819 	case V4L2_PIX_FMT_YUYV:
820 	case V4L2_PIX_FMT_RGB565:
821 		offset = image->rect.left * 2 +
822 			image->rect.top * pix->bytesperline;
823 		break;
824 	case V4L2_PIX_FMT_RGB32:
825 	case V4L2_PIX_FMT_BGR32:
826 	case V4L2_PIX_FMT_XRGB32:
827 	case V4L2_PIX_FMT_XBGR32:
828 		offset = image->rect.left * 4 +
829 			image->rect.top * pix->bytesperline;
830 		break;
831 	case V4L2_PIX_FMT_RGB24:
832 	case V4L2_PIX_FMT_BGR24:
833 		offset = image->rect.left * 3 +
834 			image->rect.top * pix->bytesperline;
835 		break;
836 	case V4L2_PIX_FMT_SBGGR8:
837 	case V4L2_PIX_FMT_SGBRG8:
838 	case V4L2_PIX_FMT_SGRBG8:
839 	case V4L2_PIX_FMT_SRGGB8:
840 	case V4L2_PIX_FMT_GREY:
841 		offset = image->rect.left + image->rect.top * pix->bytesperline;
842 		break;
843 	case V4L2_PIX_FMT_SBGGR16:
844 	case V4L2_PIX_FMT_SGBRG16:
845 	case V4L2_PIX_FMT_SGRBG16:
846 	case V4L2_PIX_FMT_SRGGB16:
847 	case V4L2_PIX_FMT_Y16:
848 		offset = image->rect.left * 2 +
849 			 image->rect.top * pix->bytesperline;
850 		break;
851 	default:
852 		/* This should not happen */
853 		WARN_ON(1);
854 		offset = 0;
855 		ret = -EINVAL;
856 	}
857 
858 	ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
859 	ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
860 
861 	return ret;
862 }
863 EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
864 
865 void ipu_cpmem_dump(struct ipuv3_channel *ch)
866 {
867 	struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
868 	struct ipu_soc *ipu = ch->ipu;
869 	int chno = ch->num;
870 
871 	dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
872 		readl(&p->word[0].data[0]),
873 		readl(&p->word[0].data[1]),
874 		readl(&p->word[0].data[2]),
875 		readl(&p->word[0].data[3]),
876 		readl(&p->word[0].data[4]));
877 	dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
878 		readl(&p->word[1].data[0]),
879 		readl(&p->word[1].data[1]),
880 		readl(&p->word[1].data[2]),
881 		readl(&p->word[1].data[3]),
882 		readl(&p->word[1].data[4]));
883 	dev_dbg(ipu->dev, "PFS 0x%x, ",
884 		 ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
885 	dev_dbg(ipu->dev, "BPP 0x%x, ",
886 		ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
887 	dev_dbg(ipu->dev, "NPB 0x%x\n",
888 		 ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
889 
890 	dev_dbg(ipu->dev, "FW %d, ",
891 		 ipu_ch_param_read_field(ch, IPU_FIELD_FW));
892 	dev_dbg(ipu->dev, "FH %d, ",
893 		 ipu_ch_param_read_field(ch, IPU_FIELD_FH));
894 	dev_dbg(ipu->dev, "EBA0 0x%x\n",
895 		 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
896 	dev_dbg(ipu->dev, "EBA1 0x%x\n",
897 		 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
898 	dev_dbg(ipu->dev, "Stride %d\n",
899 		 ipu_ch_param_read_field(ch, IPU_FIELD_SL));
900 	dev_dbg(ipu->dev, "scan_order %d\n",
901 		 ipu_ch_param_read_field(ch, IPU_FIELD_SO));
902 	dev_dbg(ipu->dev, "uv_stride %d\n",
903 		 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
904 	dev_dbg(ipu->dev, "u_offset 0x%x\n",
905 		 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
906 	dev_dbg(ipu->dev, "v_offset 0x%x\n",
907 		 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
908 
909 	dev_dbg(ipu->dev, "Width0 %d+1, ",
910 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
911 	dev_dbg(ipu->dev, "Width1 %d+1, ",
912 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
913 	dev_dbg(ipu->dev, "Width2 %d+1, ",
914 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
915 	dev_dbg(ipu->dev, "Width3 %d+1, ",
916 		 ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
917 	dev_dbg(ipu->dev, "Offset0 %d, ",
918 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
919 	dev_dbg(ipu->dev, "Offset1 %d, ",
920 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
921 	dev_dbg(ipu->dev, "Offset2 %d, ",
922 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
923 	dev_dbg(ipu->dev, "Offset3 %d\n",
924 		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
925 }
926 EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
927 
928 int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
929 {
930 	struct ipu_cpmem *cpmem;
931 
932 	cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
933 	if (!cpmem)
934 		return -ENOMEM;
935 
936 	ipu->cpmem_priv = cpmem;
937 
938 	spin_lock_init(&cpmem->lock);
939 	cpmem->base = devm_ioremap(dev, base, SZ_128K);
940 	if (!cpmem->base)
941 		return -ENOMEM;
942 
943 	dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
944 		base, cpmem->base);
945 	cpmem->ipu = ipu;
946 
947 	return 0;
948 }
949 
950 void ipu_cpmem_exit(struct ipu_soc *ipu)
951 {
952 }
953