Linux Audio

Check our new training course

Loading...
v5.4
  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
 13struct ipu_cpmem_word {
 14	u32 data[5];
 15	u32 res[3];
 16};
 17
 18struct ipu_ch_param {
 19	struct ipu_cpmem_word word[2];
 20};
 21
 22struct 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
 92static inline struct ipu_ch_param __iomem *
 93ipu_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
100static 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
126static 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 */
162static 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
228void 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}
237EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
238
239void 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}
244EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
245
246void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
247{
248	ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
249}
250EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
251
252void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
253{
254	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
255}
256EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
257
258void 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};
270EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
271
272void 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}
281EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
282
283void 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}
290EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
291
292void 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};
331EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
332
333void 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}
338EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
339
340int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
341{
342	return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
343}
344EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
345
346void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
347{
348	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
349};
350EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
351
352void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
353{
354	ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
355}
356EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
357
358void 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}
365EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
366
367int 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}
420EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
421
422int 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}
453EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
454
455void 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}
470EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
471
472void 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}
482EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
483
484static 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
492static 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
500static 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
508static 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
516static 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
524static 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
532static 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
540static 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
548static 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
556static 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
564static 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
572static 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
580static 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. */
607static 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
622static 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
641int 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}
762EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
763
764int 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}
887EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
888
889void 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}
950EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
951
952int 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
974void ipu_cpmem_exit(struct ipu_soc *ipu)
975{
976}
v6.13.7
  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
 13struct ipu_cpmem_word {
 14	u32 data[5];
 15	u32 res[3];
 16};
 17
 18struct ipu_ch_param {
 19	struct ipu_cpmem_word word[2];
 20};
 21
 22struct 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
 92static inline struct ipu_ch_param __iomem *
 93ipu_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
100static 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
126static 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 */
162static 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
228void 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}
237EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
238
239void 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}
244EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
245
246void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
247{
248	ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
249}
250EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
251
252void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
253{
254	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
255}
256EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
257
258void 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};
270EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
271
272void 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}
281EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
282
283void 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}
290EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
291
292void 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};
331EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
332
333void 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}
338EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
339
340int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
341{
342	return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
343}
344EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
345
346void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
347{
348	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
349};
350EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
351
352void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
353{
354	ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
355}
356EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
357
358void 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}
365EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
366
367int 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}
420EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
421
422int 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}
453EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
454
455void 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}
470EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
471
472void 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}
482EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
483
484static 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
492static 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
500static 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
508static 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
516static 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
524static 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
532static 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
540static 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
548static 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
556static 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
564static 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
572static 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
580static 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->bytesperline * (y))
589#define U_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
590				 (pix->bytesperline * ((y) / 2) / 2) + (x) / 2)
591#define V_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
592				 (pix->bytesperline * pix->height / 4) + \
593				 (pix->bytesperline * ((y) / 2) / 2) + (x) / 2)
594#define U2_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
595				 (pix->bytesperline * (y) / 2) + (x) / 2)
596#define V2_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
597				 (pix->bytesperline * pix->height / 2) + \
598				 (pix->bytesperline * (y) / 2) + (x) / 2)
599#define UV_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
600				 (pix->bytesperline * ((y) / 2)) + (x))
601#define UV2_OFFSET(pix, x, y)	((pix->bytesperline * pix->height) +	 \
602				 (pix->bytesperline * y) + (x))
603
604#define NUM_ALPHA_CHANNELS	7
605
606/* See Table 37-12. Alpha channels mapping. */
607static 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
622static 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
641int 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}
762EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
763
764int 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}
887EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
888
889void 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}
950EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
951
952int 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
974void ipu_cpmem_exit(struct ipu_soc *ipu)
975{
976}