1
2
3
4
5
6
7
8
9
10#include <linux/device.h>
11
12#include <media/v4l2-subdev.h>
13
14#include "vsp1.h"
15#include "vsp1_dl.h"
16#include "vsp1_pipe.h"
17#include "vsp1_rwpf.h"
18#include "vsp1_video.h"
19
20#define RPF_MAX_WIDTH 8190
21#define RPF_MAX_HEIGHT 8190
22
23
24
25
26
27static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
28 struct vsp1_dl_body *dlb, u32 reg, u32 data)
29{
30 vsp1_dl_body_write(dlb, reg + rpf->entity.index * VI6_RPF_OFFSET,
31 data);
32}
33
34
35
36
37
38static const struct v4l2_subdev_ops rpf_ops = {
39 .pad = &vsp1_rwpf_pad_ops,
40};
41
42
43
44
45
46static void rpf_configure_stream(struct vsp1_entity *entity,
47 struct vsp1_pipeline *pipe,
48 struct vsp1_dl_body *dlb)
49{
50 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
51 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
52 const struct v4l2_pix_format_mplane *format = &rpf->format;
53 const struct v4l2_mbus_framefmt *source_format;
54 const struct v4l2_mbus_framefmt *sink_format;
55 unsigned int left = 0;
56 unsigned int top = 0;
57 u32 pstride;
58 u32 infmt;
59
60
61 pstride = format->plane_fmt[0].bytesperline
62 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
63 if (format->num_planes > 1)
64 pstride |= format->plane_fmt[1].bytesperline
65 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
66
67 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride);
68
69
70 sink_format = vsp1_entity_get_pad_format(&rpf->entity,
71 rpf->entity.config,
72 RWPF_PAD_SINK);
73 source_format = vsp1_entity_get_pad_format(&rpf->entity,
74 rpf->entity.config,
75 RWPF_PAD_SOURCE);
76
77 infmt = VI6_RPF_INFMT_CIPM
78 | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
79
80 if (fmtinfo->swap_yc)
81 infmt |= VI6_RPF_INFMT_SPYCS;
82 if (fmtinfo->swap_uv)
83 infmt |= VI6_RPF_INFMT_SPUVS;
84
85 if (sink_format->code != source_format->code)
86 infmt |= VI6_RPF_INFMT_CSC;
87
88 vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt);
89 vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap);
90
91
92 if (pipe->brx) {
93 const struct v4l2_rect *compose;
94
95 compose = vsp1_entity_get_pad_selection(pipe->brx,
96 pipe->brx->config,
97 rpf->brx_input,
98 V4L2_SEL_TGT_COMPOSE);
99 left = compose->left;
100 top = compose->top;
101 }
102
103 vsp1_rpf_write(rpf, dlb, VI6_RPF_LOC,
104 (left << VI6_RPF_LOC_HCOORD_SHIFT) |
105 (top << VI6_RPF_LOC_VCOORD_SHIFT));
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 vsp1_rpf_write(rpf, dlb, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
131 (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
132 : VI6_RPF_ALPH_SEL_ASEL_FIXED));
133
134 if (entity->vsp1->info->gen == 3) {
135 u32 mult;
136
137 if (fmtinfo->alpha) {
138
139
140
141
142
143
144
145
146 bool premultiplied = format->flags
147 & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
148
149 mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO
150 | (premultiplied ?
151 VI6_RPF_MULT_ALPHA_P_MMD_RATIO :
152 VI6_RPF_MULT_ALPHA_P_MMD_NONE);
153 } else {
154
155
156
157
158
159
160 mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE
161 | VI6_RPF_MULT_ALPHA_P_MMD_NONE;
162 }
163
164 rpf->mult_alpha = mult;
165 }
166
167 vsp1_rpf_write(rpf, dlb, VI6_RPF_MSK_CTRL, 0);
168 vsp1_rpf_write(rpf, dlb, VI6_RPF_CKEY_CTRL, 0);
169
170}
171
172static void rpf_configure_frame(struct vsp1_entity *entity,
173 struct vsp1_pipeline *pipe,
174 struct vsp1_dl_list *dl,
175 struct vsp1_dl_body *dlb)
176{
177 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
178
179 vsp1_rpf_write(rpf, dlb, VI6_RPF_VRTCOL_SET,
180 rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
181 vsp1_rpf_write(rpf, dlb, VI6_RPF_MULT_ALPHA, rpf->mult_alpha |
182 (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT));
183
184 vsp1_pipeline_propagate_alpha(pipe, dlb, rpf->alpha);
185}
186
187static void rpf_configure_partition(struct vsp1_entity *entity,
188 struct vsp1_pipeline *pipe,
189 struct vsp1_dl_list *dl,
190 struct vsp1_dl_body *dlb)
191{
192 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
193 struct vsp1_rwpf_memory mem = rpf->mem;
194 struct vsp1_device *vsp1 = rpf->entity.vsp1;
195 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
196 const struct v4l2_pix_format_mplane *format = &rpf->format;
197 struct v4l2_rect crop;
198
199
200
201
202
203
204
205
206
207 crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config);
208
209
210
211
212
213
214
215
216
217
218
219 if (pipe->partitions > 1) {
220 crop.width = pipe->partition->rpf.width;
221 crop.left += pipe->partition->rpf.left;
222 }
223
224 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_BSIZE,
225 (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
226 (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
227 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRC_ESIZE,
228 (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
229 (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
230
231 mem.addr[0] += crop.top * format->plane_fmt[0].bytesperline
232 + crop.left * fmtinfo->bpp[0] / 8;
233
234 if (format->num_planes > 1) {
235 unsigned int offset;
236
237 offset = crop.top * format->plane_fmt[1].bytesperline
238 + crop.left / fmtinfo->hsub
239 * fmtinfo->bpp[1] / 8;
240 mem.addr[1] += offset;
241 mem.addr[2] += offset;
242 }
243
244
245
246
247
248 if (vsp1->info->gen == 3 && format->num_planes == 3 &&
249 fmtinfo->swap_uv)
250 swap(mem.addr[1], mem.addr[2]);
251
252 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_Y, mem.addr[0]);
253 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C0, mem.addr[1]);
254 vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_ADDR_C1, mem.addr[2]);
255}
256
257static void rpf_partition(struct vsp1_entity *entity,
258 struct vsp1_pipeline *pipe,
259 struct vsp1_partition *partition,
260 unsigned int partition_idx,
261 struct vsp1_partition_window *window)
262{
263 partition->rpf = *window;
264}
265
266static const struct vsp1_entity_operations rpf_entity_ops = {
267 .configure_stream = rpf_configure_stream,
268 .configure_frame = rpf_configure_frame,
269 .configure_partition = rpf_configure_partition,
270 .partition = rpf_partition,
271};
272
273
274
275
276
277struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
278{
279 struct vsp1_rwpf *rpf;
280 char name[6];
281 int ret;
282
283 rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
284 if (rpf == NULL)
285 return ERR_PTR(-ENOMEM);
286
287 rpf->max_width = RPF_MAX_WIDTH;
288 rpf->max_height = RPF_MAX_HEIGHT;
289
290 rpf->entity.ops = &rpf_entity_ops;
291 rpf->entity.type = VSP1_ENTITY_RPF;
292 rpf->entity.index = index;
293
294 sprintf(name, "rpf.%u", index);
295 ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops,
296 MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
297 if (ret < 0)
298 return ERR_PTR(ret);
299
300
301 ret = vsp1_rwpf_init_ctrls(rpf, 0);
302 if (ret < 0) {
303 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
304 index);
305 goto error;
306 }
307
308 v4l2_ctrl_handler_setup(&rpf->ctrls);
309
310 return rpf;
311
312error:
313 vsp1_entity_destroy(&rpf->entity);
314 return ERR_PTR(ret);
315}
316