xref: /linux/drivers/media/platform/renesas/vsp1/vsp1_pipe.c (revision b4ada0618eed0fbd1b1630f73deb048c592b06a1)
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 
33 static 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 
214 static 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 
221 static 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  */
240 const 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  */
286 const struct vsp1_format_info *
287 vsp1_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  */
367 void 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 
407 void 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 
439 void 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 
450 void __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. */
473 void 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 
488 bool 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 
500 int 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 
551 bool 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 
562 void 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  */
600 void 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  */
629 static 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  */
652 void 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 }
708