File Index
Files and directories
Sign in
FILE

vsp1_pipe.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/renesas/vsp1/vsp1_pipe.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * vsp1_pipe.c  --  R-Car VSP1 Pipeline
  4 *
  5 * Copyright (C) 2013-2015 Renesas Electronics Corporation
  6 *
  7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  8 */
  9
 10#include <linux/delay.h>
 11#include <linux/list.h>
 12#include <linux/lockdep.h>
 13#include <linux/sched.h>
 14#include <linux/wait.h>
 15
 16#include <media/media-entity.h>
 17#include <media/v4l2-subdev.h>
 18
 19#include "vsp1.h"
 20#include "vsp1_brx.h"
 21#include "vsp1_dl.h"
 22#include "vsp1_entity.h"
 23#include "vsp1_hgo.h"
 24#include "vsp1_hgt.h"
 25#include "vsp1_pipe.h"
 26#include "vsp1_rwpf.h"
 27#include "vsp1_uds.h"
 28
 29/* -----------------------------------------------------------------------------
 30 * Helper Functions
 31 */
 32
 33static const struct vsp1_format_info vsp1_video_formats[] = {
 34	{ V4L2_PIX_FMT_RGB332, MEDIA_BUS_FMT_ARGB8888_1X32,
 35	  VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 36	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
 37	  1, { 8, 0, 0 }, false, false, 1, 1, false },
 38	{ V4L2_PIX_FMT_ARGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
 39	  VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 40	  VI6_RPF_DSWAP_P_WDS,
 41	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 42	{ V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
 43	  VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 44	  VI6_RPF_DSWAP_P_WDS,
 45	  1, { 16, 0, 0 }, false, false, 1, 1, false },
 46	{ V4L2_PIX_FMT_RGBA444, MEDIA_BUS_FMT_ARGB8888_1X32,
 47	  VI6_FMT_RGBA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 48	  VI6_RPF_DSWAP_P_WDS,
 49	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 50	{ V4L2_PIX_FMT_RGBX444, MEDIA_BUS_FMT_ARGB8888_1X32,
 51	  VI6_FMT_RGBX_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 52	  VI6_RPF_DSWAP_P_WDS,
 53	  1, { 16, 0, 0 }, false, false, 1, 1, false },
 54	{ V4L2_PIX_FMT_ABGR444, MEDIA_BUS_FMT_ARGB8888_1X32,
 55	  VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 56	  VI6_RPF_DSWAP_P_WDS,
 57	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 58	{ V4L2_PIX_FMT_XBGR444, MEDIA_BUS_FMT_ARGB8888_1X32,
 59	  VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 60	  VI6_RPF_DSWAP_P_WDS,
 61	  1, { 16, 0, 0 }, false, false, 1, 1, false },
 62	{ V4L2_PIX_FMT_BGRA444, MEDIA_BUS_FMT_ARGB8888_1X32,
 63	  VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 64	  VI6_RPF_DSWAP_P_WDS,
 65	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 66	{ V4L2_PIX_FMT_BGRX444, MEDIA_BUS_FMT_ARGB8888_1X32,
 67	  VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 68	  VI6_RPF_DSWAP_P_WDS,
 69	  1, { 16, 0, 0 }, false, false, 1, 1, false },
 70	{ V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
 71	  VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 72	  VI6_RPF_DSWAP_P_WDS,
 73	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 74	{ V4L2_PIX_FMT_XRGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
 75	  VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 76	  VI6_RPF_DSWAP_P_WDS,
 77	  1, { 16, 0, 0 }, false, false, 1, 1, false },
 78	{ V4L2_PIX_FMT_RGBA555, MEDIA_BUS_FMT_ARGB8888_1X32,
 79	  VI6_FMT_RGBA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 80	  VI6_RPF_DSWAP_P_WDS,
 81	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 82	{ V4L2_PIX_FMT_RGBX555, MEDIA_BUS_FMT_ARGB8888_1X32,
 83	  VI6_FMT_RGBX_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 84	  VI6_RPF_DSWAP_P_WDS,
 85	  1, { 16, 0, 0 }, false, false, 1, 1, false },
 86	{ V4L2_PIX_FMT_ABGR555, MEDIA_BUS_FMT_ARGB8888_1X32,
 87	  VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 88	  VI6_RPF_DSWAP_P_WDS,
 89	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 90	{ V4L2_PIX_FMT_XBGR555, MEDIA_BUS_FMT_ARGB8888_1X32,
 91	  VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 92	  VI6_RPF_DSWAP_P_WDS,
 93	  1, { 16, 0, 0 }, false, false, 1, 1, false },
 94	{ V4L2_PIX_FMT_BGRA555, MEDIA_BUS_FMT_ARGB8888_1X32,
 95	  VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 96	  VI6_RPF_DSWAP_P_WDS,
 97	  1, { 16, 0, 0 }, false, false, 1, 1, true },
 98	{ V4L2_PIX_FMT_BGRX555, MEDIA_BUS_FMT_ARGB8888_1X32,
 99	  VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
100	  VI6_RPF_DSWAP_P_WDS,
101	  1, { 16, 0, 0 }, false, false, 1, 1, false },
102	{ V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32,
103	  VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
104	  VI6_RPF_DSWAP_P_WDS,
105	  1, { 16, 0, 0 }, false, false, 1, 1, false },
106	{ V4L2_PIX_FMT_BGR24, MEDIA_BUS_FMT_ARGB8888_1X32,
107	  VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
108	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
109	  1, { 24, 0, 0 }, false, false, 1, 1, false },
110	{ V4L2_PIX_FMT_RGB24, MEDIA_BUS_FMT_ARGB8888_1X32,
111	  VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
112	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
113	  1, { 24, 0, 0 }, false, false, 1, 1, false },
114	{ V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
115	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
116	  1, { 32, 0, 0 }, false, false, 1, 1, true },
117	{ V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
118	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
119	  1, { 32, 0, 0 }, false, false, 1, 1, false },
120	{ V4L2_PIX_FMT_BGRA32, MEDIA_BUS_FMT_ARGB8888_1X32,
121	  VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
122	  1, { 32, 0, 0 }, false, false, 1, 1, true },
123	{ V4L2_PIX_FMT_BGRX32, MEDIA_BUS_FMT_ARGB8888_1X32,
124	  VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
125	  1, { 32, 0, 0 }, false, false, 1, 1, false },
126	{ V4L2_PIX_FMT_RGBA32, MEDIA_BUS_FMT_ARGB8888_1X32,
127	  VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
128	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
129	  1, { 32, 0, 0 }, false, false, 1, 1, true },
130	{ V4L2_PIX_FMT_RGBX32, MEDIA_BUS_FMT_ARGB8888_1X32,
131	  VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
132	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
133	  1, { 32, 0, 0 }, false, false, 1, 1, false },
134	{ V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
135	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
136	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
137	  1, { 32, 0, 0 }, false, false, 1, 1, true },
138	{ V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
139	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
140	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
141	  1, { 32, 0, 0 }, false, false, 1, 1, false },
142	{ V4L2_PIX_FMT_RGBX1010102, MEDIA_BUS_FMT_ARGB8888_1X32,
143	  VI6_FMT_RGB10_RGB10A2_A2RGB10,
144	  VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
145	  1, { 32, 0, 0 }, false, false, 1, 1, false },
146	{ V4L2_PIX_FMT_RGBA1010102, MEDIA_BUS_FMT_ARGB8888_1X32,
147	  VI6_FMT_RGB10_RGB10A2_A2RGB10,
148	  VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
149	  1, { 32, 0, 0 }, false, false, 1, 1, false },
150	{ V4L2_PIX_FMT_ARGB2101010, MEDIA_BUS_FMT_ARGB8888_1X32,
151	  VI6_FMT_RGB10_RGB10A2_A2RGB10,
152	  VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
153	  1, { 32, 0, 0 }, false, false, 1, 1, false },
154	{ V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32,
155	  VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
156	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
157	  1, { 16, 0, 0 }, false, false, 2, 1, false },
158	{ V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32,
159	  VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
160	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
161	  1, { 16, 0, 0 }, true, false, 2, 1, false },
162	{ V4L2_PIX_FMT_YVYU, MEDIA_BUS_FMT_AYUV8_1X32,
163	  VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
164	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
165	  1, { 16, 0, 0 }, true, true, 2, 1, false },
166	{ V4L2_PIX_FMT_NV12M, MEDIA_BUS_FMT_AYUV8_1X32,
167	  VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
168	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
169	  2, { 8, 16, 0 }, false, false, 2, 2, false },
170	{ V4L2_PIX_FMT_NV21M, MEDIA_BUS_FMT_AYUV8_1X32,
171	  VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
172	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
173	  2, { 8, 16, 0 }, false, true, 2, 2, false },
174	{ V4L2_PIX_FMT_NV16M, MEDIA_BUS_FMT_AYUV8_1X32,
175	  VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
176	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
177	  2, { 8, 16, 0 }, false, false, 2, 1, false },
178	{ V4L2_PIX_FMT_NV61M, MEDIA_BUS_FMT_AYUV8_1X32,
179	  VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
180	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
181	  2, { 8, 16, 0 }, false, true, 2, 1, false },
182	{ V4L2_PIX_FMT_YUV420M, MEDIA_BUS_FMT_AYUV8_1X32,
183	  VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
184	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
185	  3, { 8, 8, 8 }, false, false, 2, 2, false },
186	{ V4L2_PIX_FMT_YVU420M, MEDIA_BUS_FMT_AYUV8_1X32,
187	  VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
188	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
189	  3, { 8, 8, 8 }, false, true, 2, 2, false },
190	{ V4L2_PIX_FMT_YUV422M, MEDIA_BUS_FMT_AYUV8_1X32,
191	  VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
192	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
193	  3, { 8, 8, 8 }, false, false, 2, 1, false },
194	{ V4L2_PIX_FMT_YVU422M, MEDIA_BUS_FMT_AYUV8_1X32,
195	  VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
196	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
197	  3, { 8, 8, 8 }, false, true, 2, 1, false },
198	{ V4L2_PIX_FMT_YUV444M, MEDIA_BUS_FMT_AYUV8_1X32,
199	  VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
200	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
201	  3, { 8, 8, 8 }, false, false, 1, 1, false },
202	{ V4L2_PIX_FMT_YVU444M, MEDIA_BUS_FMT_AYUV8_1X32,
203	  VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
204	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
205	  3, { 8, 8, 8 }, false, true, 1, 1, false },
206	{ V4L2_PIX_FMT_Y210, MEDIA_BUS_FMT_AYUV8_1X32,
207	  VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
208	  1, { 32, 0, 0 }, false, false, 2, 1, false },
209	{ V4L2_PIX_FMT_Y212, MEDIA_BUS_FMT_AYUV8_1X32,
210	  VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
211	  1, { 32, 0, 0 }, false, false, 2, 1, false },
212};
213
214static const struct vsp1_format_info vsp1_video_gen2_formats[] = {
215	{ V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32,
216	  VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
217	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
218	  1, { 16, 0, 0 }, false, true, 2, 1, false },
219};
220
221static const struct vsp1_format_info vsp1_video_hsit_formats[] = {
222	{ V4L2_PIX_FMT_HSV24, MEDIA_BUS_FMT_AHSV8888_1X32,
223	  VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
224	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
225	  1, { 24, 0, 0 }, false, false, 1, 1, false },
226	{ V4L2_PIX_FMT_HSV32, MEDIA_BUS_FMT_AHSV8888_1X32,
227	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
228	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
229	  1, { 32, 0, 0 }, false, false, 1, 1, false },
230};
231
232/**
233 * vsp1_get_format_info - Retrieve format information for a 4CC
234 * @vsp1: the VSP1 device
235 * @fourcc: the format 4CC
236 *
237 * Return a pointer to the format information structure corresponding to the
238 * given V4L2 format 4CC, or NULL if no corresponding format can be found.
239 */
240const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1,
241						    u32 fourcc)
242{
243	unsigned int i;
244
245	for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) {
246		const struct vsp1_format_info *info = &vsp1_video_formats[i];
247
248		if (info->fourcc == fourcc)
249			return info;
250	}
251
252	if (vsp1->info->gen == 2) {
253		for (i = 0; i < ARRAY_SIZE(vsp1_video_gen2_formats); ++i) {
254			const struct vsp1_format_info *info =
255				&vsp1_video_gen2_formats[i];
256
257			if (info->fourcc == fourcc)
258				return info;
259		}
260	}
261
262	if (vsp1_feature(vsp1, VSP1_HAS_HSIT)) {
263		for (i = 0; i < ARRAY_SIZE(vsp1_video_hsit_formats); ++i) {
264			const struct vsp1_format_info *info =
265				&vsp1_video_hsit_formats[i];
266
267			if (info->fourcc == fourcc)
268				return info;
269		}
270	}
271
272	return NULL;
273}
274
275/**
276 * vsp1_get_format_info_by_index - Enumerate format information
277 * @vsp1: the VSP1 device
278 * @index: the format index
279 * @code: media bus code to limit enumeration
280 *
281 * Return a pointer to the format information structure corresponding to the
282 * given index, or NULL if the index exceeds the supported formats list. If the
283 * @code parameter is not zero, only formats compatible with the media bus code
284 * will be enumerated.
285 */
286const struct vsp1_format_info *
287vsp1_get_format_info_by_index(struct vsp1_device *vsp1, unsigned int index,
288			      u32 code)
289{
290	unsigned int i;
291
292	if (!code) {
293		if (index < ARRAY_SIZE(vsp1_video_formats))
294			return &vsp1_video_formats[index];
295
296		if (vsp1->info->gen == 2) {
297			index -= ARRAY_SIZE(vsp1_video_formats);
298			if (index < ARRAY_SIZE(vsp1_video_gen2_formats))
299				return &vsp1_video_gen2_formats[index];
300		}
301
302		if (vsp1_feature(vsp1, VSP1_HAS_HSIT)) {
303			index -= ARRAY_SIZE(vsp1_video_gen2_formats);
304			if (index < ARRAY_SIZE(vsp1_video_hsit_formats))
305				return &vsp1_video_hsit_formats[index];
306		}
307
308		return NULL;
309	}
310
311	for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) {
312		const struct vsp1_format_info *info = &vsp1_video_formats[i];
313
314		if (info->mbus == code) {
315			if (!index)
316				return info;
317			index--;
318		}
319	}
320
321	if (vsp1->info->gen == 2) {
322		for (i = 0; i < ARRAY_SIZE(vsp1_video_gen2_formats); ++i) {
323			const struct vsp1_format_info *info =
324				&vsp1_video_gen2_formats[i];
325
326			if (info->mbus == code) {
327				if (!index)
328					return info;
329				index--;
330			}
331		}
332	}
333
334	if (vsp1_feature(vsp1, VSP1_HAS_HSIT)) {
335		for (i = 0; i < ARRAY_SIZE(vsp1_video_hsit_formats); ++i) {
336			const struct vsp1_format_info *info =
337				&vsp1_video_hsit_formats[i];
338
339			if (info->mbus == code) {
340				if (!index)
341					return info;
342				index--;
343			}
344		}
345	}
346
347	return NULL;
348}
349
350/**
351 * vsp1_adjust_color_space - Adjust color space fields in a format
352 * @code: the media bus code
353 * @colorspace: the colorspace
354 * @xfer_func: the transfer function
355 * @encoding: the encoding
356 * @quantization: the quantization
357 *
358 * This function adjusts all color space fields of a video device of subdev
359 * format structure, taking into account the requested format, requested color
360 * space and limitations of the VSP1. It should be used in the video device and
361 * subdev set format handlers.
362 *
363 * The colorspace and xfer_func fields are freely configurable, as they are out
364 * of scope for VSP processing. The encoding and quantization is hardcoded for
365 * non-YUV formats, and can be configured for YUV formats.
366 */
367void vsp1_adjust_color_space(u32 code, u32 *colorspace, u8 *xfer_func,
368			     u8 *encoding, u8 *quantization)
369{
370	if (*colorspace == V4L2_COLORSPACE_DEFAULT ||
371	    *colorspace >= V4L2_COLORSPACE_LAST)
372		*colorspace = code == MEDIA_BUS_FMT_AYUV8_1X32
373			    ? V4L2_COLORSPACE_SMPTE170M
374			    : V4L2_COLORSPACE_SRGB;
375
376	if (*xfer_func == V4L2_XFER_FUNC_DEFAULT ||
377	    *xfer_func >= V4L2_XFER_FUNC_LAST)
378		*xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(*colorspace);
379
380	switch (code) {
381	case MEDIA_BUS_FMT_ARGB8888_1X32:
382	default:
383		*encoding = V4L2_YCBCR_ENC_601;
384		*quantization = V4L2_QUANTIZATION_FULL_RANGE;
385		break;
386
387	case MEDIA_BUS_FMT_AHSV8888_1X32:
388		*encoding = V4L2_HSV_ENC_256;
389		*quantization = V4L2_QUANTIZATION_FULL_RANGE;
390		break;
391
392	case MEDIA_BUS_FMT_AYUV8_1X32:
393		if (*encoding != V4L2_YCBCR_ENC_601 &&
394		    *encoding != V4L2_YCBCR_ENC_709)
395			*encoding = V4L2_YCBCR_ENC_601;
396		if (*quantization != V4L2_QUANTIZATION_FULL_RANGE &&
397		    *quantization != V4L2_QUANTIZATION_LIM_RANGE)
398			*quantization = V4L2_QUANTIZATION_LIM_RANGE;
399		break;
400	}
401}
402
403/* -----------------------------------------------------------------------------
404 * Pipeline Management
405 */
406
407void vsp1_pipeline_reset(struct vsp1_pipeline *pipe)
408{
409	struct vsp1_entity *entity;
410	unsigned int i;
411
412	if (pipe->brx) {
413		struct vsp1_brx *brx = to_brx(&pipe->brx->subdev);
414
415		for (i = 0; i < ARRAY_SIZE(brx->inputs); ++i)
416			brx->inputs[i].rpf = NULL;
417	}
418
419	for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i)
420		pipe->inputs[i] = NULL;
421
422	pipe->output = NULL;
423
424	list_for_each_entry(entity, &pipe->entities, list_pipe)
425		entity->pipe = NULL;
426
427	INIT_LIST_HEAD(&pipe->entities);
428	pipe->state = VSP1_PIPELINE_STOPPED;
429	pipe->buffers_ready = 0;
430	pipe->num_inputs = 0;
431	pipe->brx = NULL;
432	pipe->hgo = NULL;
433	pipe->hgt = NULL;
434	pipe->iif = NULL;
435	pipe->lif = NULL;
436	pipe->uds = NULL;
437}
438
439void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
440{
441	mutex_init(&pipe->lock);
442	spin_lock_init(&pipe->irqlock);
443	init_waitqueue_head(&pipe->wq);
444	kref_init(&pipe->kref);
445
446	INIT_LIST_HEAD(&pipe->entities);
447	pipe->state = VSP1_PIPELINE_STOPPED;
448}
449
450void __vsp1_pipeline_dump(struct _ddebug *dbg, struct vsp1_pipeline *pipe,
451			  const char *msg)
452{
453	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
454	struct vsp1_entity *entity;
455	bool first = true;
456
457	printk(KERN_DEBUG "%s: %s: pipe: ", dev_name(vsp1->dev), msg);
458
459	list_for_each_entry(entity, &pipe->entities, list_pipe) {
460		const char *name;
461
462		name = strchrnul(entity->subdev.name, ' ');
463		name = name ? name + 1 : entity->subdev.name;
464
465		pr_cont("%s%s", first ? "" : ", ", name);
466		first = false;
467	}
468
469	pr_cont("\n");
470}
471
472/* Must be called with the pipe irqlock held. */
473void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
474{
475	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
476
477	lockdep_assert_held(&pipe->irqlock);
478
479	if (pipe->state == VSP1_PIPELINE_STOPPED) {
480		vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index),
481			   VI6_CMD_STRCMD);
482		pipe->state = VSP1_PIPELINE_RUNNING;
483	}
484
485	pipe->buffers_ready = 0;
486}
487
488bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe)
489{
490	unsigned long flags;
491	bool stopped;
492
493	spin_lock_irqsave(&pipe->irqlock, flags);
494	stopped = pipe->state == VSP1_PIPELINE_STOPPED;
495	spin_unlock_irqrestore(&pipe->irqlock, flags);
496
497	return stopped;
498}
499
500int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
501{
502	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
503	struct vsp1_entity *entity;
504	unsigned long flags;
505	int ret;
506
507	if (pipe->lif) {
508		/*
509		 * When using display lists in continuous frame mode the only
510		 * way to stop the pipeline is to reset the hardware.
511		 */
512		ret = vsp1_reset_wpf(vsp1, pipe->output->entity.index);
513		if (ret == 0) {
514			spin_lock_irqsave(&pipe->irqlock, flags);
515			pipe->state = VSP1_PIPELINE_STOPPED;
516			spin_unlock_irqrestore(&pipe->irqlock, flags);
517		}
518	} else {
519		/* Otherwise just request a stop and wait. */
520		spin_lock_irqsave(&pipe->irqlock, flags);
521		if (pipe->state == VSP1_PIPELINE_RUNNING)
522			pipe->state = VSP1_PIPELINE_STOPPING;
523		spin_unlock_irqrestore(&pipe->irqlock, flags);
524
525		ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
526					 msecs_to_jiffies(500));
527		ret = ret == 0 ? -ETIMEDOUT : 0;
528	}
529
530	list_for_each_entry(entity, &pipe->entities, list_pipe) {
531		if (entity->route && entity->route->reg)
532			vsp1_write(vsp1, entity->route->reg,
533				   VI6_DPR_NODE_UNUSED);
534	}
535
536	if (pipe->hgo)
537		vsp1_write(vsp1, VI6_DPR_HGO_SMPPT,
538			   (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
539			   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
540
541	if (pipe->hgt)
542		vsp1_write(vsp1, VI6_DPR_HGT_SMPPT,
543			   (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
544			   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
545
546	vsp1_wpf_stop(pipe->output);
547
548	return ret;
549}
550
551bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
552{
553	unsigned int mask;
554
555	mask = ((1 << pipe->num_inputs) - 1) << 1;
556	if (!pipe->lif)
557		mask |= 1 << 0;
558
559	return pipe->buffers_ready == mask;
560}
561
562void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
563{
564	unsigned int flags;
565
566	if (pipe == NULL)
567		return;
568
569	/*
570	 * If the DL commit raced with the frame end interrupt, the commit ends
571	 * up being postponed by one frame. The returned flags tell whether the
572	 * active frame was finished or postponed.
573	 */
574	flags = vsp1_dlm_irq_frame_end(pipe->output->dlm);
575
576	if (pipe->hgo)
577		vsp1_hgo_frame_end(pipe->hgo);
578
579	if (pipe->hgt)
580		vsp1_hgt_frame_end(pipe->hgt);
581
582	/*
583	 * Regardless of frame completion we still need to notify the pipe
584	 * frame_end to account for vblank events.
585	 */
586	if (pipe->frame_end)
587		pipe->frame_end(pipe, flags);
588
589	pipe->sequence++;
590}
591
592/*
593 * Propagate the alpha value through the pipeline.
594 *
595 * As the UDS has restricted scaling capabilities when the alpha component needs
596 * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
597 * value. The UDS then outputs a fixed alpha value which needs to be programmed
598 * from the input RPF alpha.
599 */
600void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
601				   struct vsp1_dl_body *dlb, unsigned int alpha)
602{
603	if (!pipe->uds)
604		return;
605
606	/*
607	 * The BRU and BRS background color has a fixed alpha value set to 255,
608	 * the output alpha value is thus always equal to 255.
609	 */
610	if (pipe->uds_input->type == VSP1_ENTITY_BRU ||
611	    pipe->uds_input->type == VSP1_ENTITY_BRS)
612		alpha = 255;
613
614	vsp1_uds_set_alpha(pipe->uds, dlb, alpha);
615}
616
617/* -----------------------------------------------------------------------------
618 * VSP1 Partition Algorithm support
619 */
620
621/*
622 * Propagate the partition calculations through the pipeline
623 *
624 * Work backwards through the pipe, allowing each entity to update the partition
625 * parameters based on its configuration, and the entity connected to its
626 * source. Each entity must produce the partition required for the previous
627 * entity in the pipeline.
628 */
629static void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
630					      struct vsp1_partition *partition,
631					      unsigned int index,
632					      struct v4l2_rect *window)
633{
634	struct vsp1_entity *entity;
635
636	list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) {
637		if (entity->ops->partition)
638			entity->ops->partition(entity, entity->state, pipe,
639					       partition, index, window);
640	}
641}
642
643/*
644 * vsp1_pipeline_calculate_partition - Calculate pipeline configuration for a
645 * partition
646 *
647 * @pipe: the pipeline
648 * @partition: partition that will hold the calculated values
649 * @div_size: pre-determined maximum partition division size
650 * @index: partition index
651 */
652void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
653				       struct vsp1_partition *partition,
654				       unsigned int div_size,
655				       unsigned int index)
656{
657	const struct v4l2_mbus_framefmt *format;
658	struct v4l2_rect window;
659	unsigned int modulus;
660
661	/*
662	 * Partitions are computed on the size before rotation, use the format
663	 * at the WPF sink.
664	 */
665	format = v4l2_subdev_state_get_format(pipe->output->entity.state,
666					      RWPF_PAD_SINK);
667
668	/* Initialise the partition with sane starting conditions. */
669	window.left = index * div_size;
670	window.width = div_size;
671	window.top = 0;
672	window.height = format->height;
673
674	modulus = format->width % div_size;
675
676	/*
677	 * We need to prevent the last partition from being smaller than the
678	 * *minimum* width of the hardware capabilities.
679	 *
680	 * If the modulus is less than half of the partition size,
681	 * the penultimate partition is reduced to half, which is added
682	 * to the final partition: |1234|1234|1234|12|341|
683	 * to prevent this:        |1234|1234|1234|1234|1|.
684	 */
685	if (modulus) {
686		/*
687		 * pipe->partitions is 1 based, whilst index is a 0 based index.
688		 * Normalise this locally.
689		 */
690		unsigned int partitions = pipe->partitions - 1;
691
692		if (modulus < div_size / 2) {
693			if (index == partitions - 1) {
694				/* Halve the penultimate partition. */
695				window.width = div_size / 2;
696			} else if (index == partitions) {
697				/* Increase the final partition. */
698				window.width = (div_size / 2) + modulus;
699				window.left -= div_size / 2;
700			}
701		} else if (index == partitions) {
702			window.width = modulus;
703		}
704	}
705
706	vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
707}
~/ Read-only file preview.