File Index
Files and directories
Sign in
FILE

ipu-cpmem.c

File preview with syntax highlighting.

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