1 // SPDX-License-Identifier: (GPL-2.0-only OR MIT)
2 /*
3 * Copyright (C) 2024 Amlogic, Inc. All rights reserved
4 */
5
6 #include <linux/build_bug.h>
7 #include <linux/cleanup.h>
8 #include <linux/media/amlogic/c3-isp-config.h>
9 #include <linux/pm_runtime.h>
10
11 #include <media/v4l2-ioctl.h>
12 #include <media/v4l2-isp.h>
13 #include <media/v4l2-mc.h>
14 #include <media/videobuf2-vmalloc.h>
15
16 #include "c3-isp-common.h"
17 #include "c3-isp-regs.h"
18
19 /*
20 * union c3_isp_params_block - Generalisation of a parameter block
21 *
22 * This union allows the driver to treat a block as a generic struct to this
23 * union and safely access the header and block-specific struct without having
24 * to resort to casting. The header member is accessed first, and the type field
25 * checked which allows the driver to determine which of the other members
26 * should be used.
27 *
28 * @header: The shared header struct embedded as the first member
29 * of all the possible other members. This member would be
30 * accessed first and the type field checked to determine
31 * which of the other members should be accessed.
32 * @awb_gains: For header.type == C3_ISP_PARAMS_BLOCK_AWB_GAINS
33 * @awb_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AWB_CONFIG
34 * @ae_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AE_CONFIG
35 * @af_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AF_CONFIG
36 * @pst_gamma: For header.type == C3_ISP_PARAMS_BLOCK_PST_GAMMA
37 * @ccm: For header.type == C3_ISP_PARAMS_BLOCK_CCM
38 * @csc: For header.type == C3_ISP_PARAMS_BLOCK_CSC
39 * @blc: For header.type == C3_ISP_PARAMS_BLOCK_BLC
40 */
41 union c3_isp_params_block {
42 struct c3_isp_params_block_header header;
43 struct c3_isp_params_awb_gains awb_gains;
44 struct c3_isp_params_awb_config awb_cfg;
45 struct c3_isp_params_ae_config ae_cfg;
46 struct c3_isp_params_af_config af_cfg;
47 struct c3_isp_params_pst_gamma pst_gamma;
48 struct c3_isp_params_ccm ccm;
49 struct c3_isp_params_csc csc;
50 struct c3_isp_params_blc blc;
51 };
52
53 typedef void (*c3_isp_block_handler)(struct c3_isp_device *isp,
54 const union c3_isp_params_block *block);
55
56 #define to_c3_isp_params_buffer(vbuf) \
57 container_of(vbuf, struct c3_isp_params_buffer, vb)
58
59 /* Hardware configuration */
60
c3_isp_params_cfg_awb_gains(struct c3_isp_device * isp,const union c3_isp_params_block * block)61 static void c3_isp_params_cfg_awb_gains(struct c3_isp_device *isp,
62 const union c3_isp_params_block *block)
63 {
64 const struct c3_isp_params_awb_gains *awb_gains = &block->awb_gains;
65
66 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
67 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL,
68 ISP_TOP_BEO_CTRL_WB_EN_MASK,
69 ISP_TOP_BEO_CTRL_WB_DIS);
70 return;
71 }
72
73 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN0,
74 ISP_LSWB_WB_GAIN0_GR_GAIN_MASK,
75 ISP_LSWB_WB_GAIN0_GR_GAIN(awb_gains->gr_gain));
76 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN0,
77 ISP_LSWB_WB_GAIN0_R_GAIN_MASK,
78 ISP_LSWB_WB_GAIN0_R_GAIN(awb_gains->r_gain));
79 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN1,
80 ISP_LSWB_WB_GAIN1_B_GAIN_MASK,
81 ISP_LSWB_WB_GAIN1_B_GAIN(awb_gains->b_gain));
82 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN1,
83 ISP_LSWB_WB_GAIN1_GB_GAIN_MASK,
84 ISP_LSWB_WB_GAIN1_GB_GAIN(awb_gains->gb_gain));
85 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN2,
86 ISP_LSWB_WB_GAIN2_IR_GAIN_MASK,
87 ISP_LSWB_WB_GAIN2_IR_GAIN(awb_gains->gb_gain));
88
89 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
90 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL,
91 ISP_TOP_BEO_CTRL_WB_EN_MASK,
92 ISP_TOP_BEO_CTRL_WB_EN);
93 }
94
c3_isp_params_awb_wt(struct c3_isp_device * isp,const struct c3_isp_params_awb_config * cfg)95 static void c3_isp_params_awb_wt(struct c3_isp_device *isp,
96 const struct c3_isp_params_awb_config *cfg)
97 {
98 unsigned int zones_num;
99 unsigned int base;
100 unsigned int data;
101 unsigned int i;
102
103 /* Set the weight address to 0 position */
104 c3_isp_write(isp, ISP_AWB_BLK_WT_ADDR, 0);
105
106 zones_num = cfg->horiz_zones_num * cfg->vert_zones_num;
107
108 /* Need to write 8 weights at once */
109 for (i = 0; i < zones_num / 8; i++) {
110 base = i * 8;
111 data = ISP_AWB_BLK_WT_DATA_WT(0, cfg->zone_weight[base + 0]) |
112 ISP_AWB_BLK_WT_DATA_WT(1, cfg->zone_weight[base + 1]) |
113 ISP_AWB_BLK_WT_DATA_WT(2, cfg->zone_weight[base + 2]) |
114 ISP_AWB_BLK_WT_DATA_WT(3, cfg->zone_weight[base + 3]) |
115 ISP_AWB_BLK_WT_DATA_WT(4, cfg->zone_weight[base + 4]) |
116 ISP_AWB_BLK_WT_DATA_WT(5, cfg->zone_weight[base + 5]) |
117 ISP_AWB_BLK_WT_DATA_WT(6, cfg->zone_weight[base + 6]) |
118 ISP_AWB_BLK_WT_DATA_WT(7, cfg->zone_weight[base + 7]);
119 c3_isp_write(isp, ISP_AWB_BLK_WT_DATA, data);
120 }
121
122 if (zones_num % 8 == 0)
123 return;
124
125 data = 0;
126 base = i * 8;
127
128 for (i = 0; i < zones_num % 8; i++)
129 data |= ISP_AWB_BLK_WT_DATA_WT(i, cfg->zone_weight[base + i]);
130
131 c3_isp_write(isp, ISP_AWB_BLK_WT_DATA, data);
132 }
133
c3_isp_params_awb_cood(struct c3_isp_device * isp,const struct c3_isp_params_awb_config * cfg)134 static void c3_isp_params_awb_cood(struct c3_isp_device *isp,
135 const struct c3_isp_params_awb_config *cfg)
136 {
137 unsigned int max_point_num;
138
139 /* The number of points is one more than the number of edges */
140 max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1;
141
142 /* Set the index address to 0 position */
143 c3_isp_write(isp, ISP_AWB_IDX_ADDR, 0);
144
145 for (unsigned int i = 0; i < max_point_num; i++)
146 c3_isp_write(isp, ISP_AWB_IDX_DATA,
147 ISP_AWB_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) |
148 ISP_AWB_IDX_DATA_VIDX_DATA(cfg->vert_coord[i]));
149 }
150
c3_isp_params_cfg_awb_config(struct c3_isp_device * isp,const union c3_isp_params_block * block)151 static void c3_isp_params_cfg_awb_config(struct c3_isp_device *isp,
152 const union c3_isp_params_block *block)
153 {
154 const struct c3_isp_params_awb_config *awb_cfg = &block->awb_cfg;
155
156 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
157 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
158 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK,
159 ISP_TOP_3A_STAT_CRTL_AWB_STAT_DIS);
160 return;
161 }
162
163 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
164 ISP_TOP_3A_STAT_CRTL_AWB_POINT_MASK,
165 ISP_TOP_3A_STAT_CRTL_AWB_POINT(awb_cfg->tap_point));
166
167 c3_isp_update_bits(isp, ISP_AWB_STAT_CTRL2,
168 ISP_AWB_STAT_CTRL2_SATUR_CTRL_MASK,
169 ISP_AWB_STAT_CTRL2_SATUR_CTRL(awb_cfg->satur_vald));
170
171 c3_isp_update_bits(isp, ISP_AWB_HV_BLKNUM,
172 ISP_AWB_HV_BLKNUM_H_NUM_MASK,
173 ISP_AWB_HV_BLKNUM_H_NUM(awb_cfg->horiz_zones_num));
174 c3_isp_update_bits(isp, ISP_AWB_HV_BLKNUM,
175 ISP_AWB_HV_BLKNUM_V_NUM_MASK,
176 ISP_AWB_HV_BLKNUM_V_NUM(awb_cfg->vert_zones_num));
177
178 c3_isp_update_bits(isp, ISP_AWB_STAT_RG, ISP_AWB_STAT_RG_MIN_VALUE_MASK,
179 ISP_AWB_STAT_RG_MIN_VALUE(awb_cfg->rg_min));
180 c3_isp_update_bits(isp, ISP_AWB_STAT_RG, ISP_AWB_STAT_RG_MAX_VALUE_MASK,
181 ISP_AWB_STAT_RG_MAX_VALUE(awb_cfg->rg_max));
182
183 c3_isp_update_bits(isp, ISP_AWB_STAT_BG, ISP_AWB_STAT_BG_MIN_VALUE_MASK,
184 ISP_AWB_STAT_BG_MIN_VALUE(awb_cfg->bg_min));
185 c3_isp_update_bits(isp, ISP_AWB_STAT_BG, ISP_AWB_STAT_BG_MAX_VALUE_MASK,
186 ISP_AWB_STAT_BG_MAX_VALUE(awb_cfg->bg_max));
187
188 c3_isp_update_bits(isp, ISP_AWB_STAT_RG_HL,
189 ISP_AWB_STAT_RG_HL_LOW_VALUE_MASK,
190 ISP_AWB_STAT_RG_HL_LOW_VALUE(awb_cfg->rg_low));
191 c3_isp_update_bits(isp, ISP_AWB_STAT_RG_HL,
192 ISP_AWB_STAT_RG_HL_HIGH_VALUE_MASK,
193 ISP_AWB_STAT_RG_HL_HIGH_VALUE(awb_cfg->rg_high));
194
195 c3_isp_update_bits(isp, ISP_AWB_STAT_BG_HL,
196 ISP_AWB_STAT_BG_HL_LOW_VALUE_MASK,
197 ISP_AWB_STAT_BG_HL_LOW_VALUE(awb_cfg->bg_low));
198 c3_isp_update_bits(isp, ISP_AWB_STAT_BG_HL,
199 ISP_AWB_STAT_BG_HL_HIGH_VALUE_MASK,
200 ISP_AWB_STAT_BG_HL_HIGH_VALUE(awb_cfg->bg_high));
201
202 c3_isp_params_awb_wt(isp, awb_cfg);
203 c3_isp_params_awb_cood(isp, awb_cfg);
204
205 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
206 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
207 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK,
208 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN);
209 }
210
c3_isp_params_ae_wt(struct c3_isp_device * isp,const struct c3_isp_params_ae_config * cfg)211 static void c3_isp_params_ae_wt(struct c3_isp_device *isp,
212 const struct c3_isp_params_ae_config *cfg)
213 {
214 unsigned int zones_num;
215 unsigned int base;
216 unsigned int data;
217 unsigned int i;
218
219 /* Set the weight address to 0 position */
220 c3_isp_write(isp, ISP_AE_BLK_WT_ADDR, 0);
221
222 zones_num = cfg->horiz_zones_num * cfg->vert_zones_num;
223
224 /* Need to write 8 weights at once */
225 for (i = 0; i < zones_num / 8; i++) {
226 base = i * 8;
227 data = ISP_AE_BLK_WT_DATA_WT(0, cfg->zone_weight[base + 0]) |
228 ISP_AE_BLK_WT_DATA_WT(1, cfg->zone_weight[base + 1]) |
229 ISP_AE_BLK_WT_DATA_WT(2, cfg->zone_weight[base + 2]) |
230 ISP_AE_BLK_WT_DATA_WT(3, cfg->zone_weight[base + 3]) |
231 ISP_AE_BLK_WT_DATA_WT(4, cfg->zone_weight[base + 4]) |
232 ISP_AE_BLK_WT_DATA_WT(5, cfg->zone_weight[base + 5]) |
233 ISP_AE_BLK_WT_DATA_WT(6, cfg->zone_weight[base + 6]) |
234 ISP_AE_BLK_WT_DATA_WT(7, cfg->zone_weight[base + 7]);
235 c3_isp_write(isp, ISP_AE_BLK_WT_DATA, data);
236 }
237
238 if (zones_num % 8 == 0)
239 return;
240
241 data = 0;
242 base = i * 8;
243
244 /* Write the last weights data */
245 for (i = 0; i < zones_num % 8; i++)
246 data |= ISP_AE_BLK_WT_DATA_WT(i, cfg->zone_weight[base + i]);
247
248 c3_isp_write(isp, ISP_AE_BLK_WT_DATA, data);
249 }
250
c3_isp_params_ae_cood(struct c3_isp_device * isp,const struct c3_isp_params_ae_config * cfg)251 static void c3_isp_params_ae_cood(struct c3_isp_device *isp,
252 const struct c3_isp_params_ae_config *cfg)
253 {
254 unsigned int max_point_num;
255
256 /* The number of points is one more than the number of edges */
257 max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1;
258
259 /* Set the index address to 0 position */
260 c3_isp_write(isp, ISP_AE_IDX_ADDR, 0);
261
262 for (unsigned int i = 0; i < max_point_num; i++)
263 c3_isp_write(isp, ISP_AE_IDX_DATA,
264 ISP_AE_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) |
265 ISP_AE_IDX_DATA_VIDX_DATA(cfg->vert_coord[i]));
266 }
267
c3_isp_params_cfg_ae_config(struct c3_isp_device * isp,const union c3_isp_params_block * block)268 static void c3_isp_params_cfg_ae_config(struct c3_isp_device *isp,
269 const union c3_isp_params_block *block)
270 {
271 const struct c3_isp_params_ae_config *ae_cfg = &block->ae_cfg;
272
273 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
274 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
275 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK,
276 ISP_TOP_3A_STAT_CRTL_AE_STAT_DIS);
277 return;
278 }
279
280 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
281 ISP_TOP_3A_STAT_CRTL_AE_POINT_MASK,
282 ISP_TOP_3A_STAT_CRTL_AE_POINT(ae_cfg->tap_point));
283
284 if (ae_cfg->tap_point == C3_ISP_AE_STATS_TAP_GE)
285 c3_isp_update_bits(isp, ISP_AE_CTRL,
286 ISP_AE_CTRL_INPUT_2LINE_MASK,
287 ISP_AE_CTRL_INPUT_2LINE_EN);
288 else
289 c3_isp_update_bits(isp, ISP_AE_CTRL,
290 ISP_AE_CTRL_INPUT_2LINE_MASK,
291 ISP_AE_CTRL_INPUT_2LINE_DIS);
292
293 c3_isp_update_bits(isp, ISP_AE_HV_BLKNUM,
294 ISP_AE_HV_BLKNUM_H_NUM_MASK,
295 ISP_AE_HV_BLKNUM_H_NUM(ae_cfg->horiz_zones_num));
296 c3_isp_update_bits(isp, ISP_AE_HV_BLKNUM,
297 ISP_AE_HV_BLKNUM_V_NUM_MASK,
298 ISP_AE_HV_BLKNUM_V_NUM(ae_cfg->vert_zones_num));
299
300 c3_isp_params_ae_wt(isp, ae_cfg);
301 c3_isp_params_ae_cood(isp, ae_cfg);
302
303 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
304 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
305 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK,
306 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN);
307 }
308
c3_isp_params_af_cood(struct c3_isp_device * isp,const struct c3_isp_params_af_config * cfg)309 static void c3_isp_params_af_cood(struct c3_isp_device *isp,
310 const struct c3_isp_params_af_config *cfg)
311 {
312 unsigned int max_point_num;
313
314 /* The number of points is one more than the number of edges */
315 max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1;
316
317 /* Set the index address to 0 position */
318 c3_isp_write(isp, ISP_AF_IDX_ADDR, 0);
319
320 for (unsigned int i = 0; i < max_point_num; i++)
321 c3_isp_write(isp, ISP_AF_IDX_DATA,
322 ISP_AF_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) |
323 ISP_AF_IDX_DATA_VIDX_DATA(cfg->vert_coord[i]));
324 }
325
c3_isp_params_cfg_af_config(struct c3_isp_device * isp,const union c3_isp_params_block * block)326 static void c3_isp_params_cfg_af_config(struct c3_isp_device *isp,
327 const union c3_isp_params_block *block)
328 {
329 const struct c3_isp_params_af_config *af_cfg = &block->af_cfg;
330
331 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
332 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
333 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK,
334 ISP_TOP_3A_STAT_CRTL_AF_STAT_DIS);
335 return;
336 }
337
338 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
339 ISP_TOP_3A_STAT_CRTL_AF_POINT_MASK,
340 ISP_TOP_3A_STAT_CRTL_AF_POINT(af_cfg->tap_point));
341
342 c3_isp_update_bits(isp, ISP_AF_HV_BLKNUM,
343 ISP_AF_HV_BLKNUM_H_NUM_MASK,
344 ISP_AF_HV_BLKNUM_H_NUM(af_cfg->horiz_zones_num));
345 c3_isp_update_bits(isp, ISP_AF_HV_BLKNUM,
346 ISP_AF_HV_BLKNUM_V_NUM_MASK,
347 ISP_AF_HV_BLKNUM_V_NUM(af_cfg->vert_zones_num));
348
349 c3_isp_params_af_cood(isp, af_cfg);
350
351 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
352 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
353 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK,
354 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN);
355 }
356
c3_isp_params_cfg_pst_gamma(struct c3_isp_device * isp,const union c3_isp_params_block * block)357 static void c3_isp_params_cfg_pst_gamma(struct c3_isp_device *isp,
358 const union c3_isp_params_block *block)
359 {
360 const struct c3_isp_params_pst_gamma *gm = &block->pst_gamma;
361 unsigned int base;
362 unsigned int i;
363
364 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
365 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
366 ISP_TOP_BED_CTRL_PST_GAMMA_EN_MASK,
367 ISP_TOP_BED_CTRL_PST_GAMMA_DIS);
368 return;
369 }
370
371 /* R, G and B channels use the same gamma lut */
372 for (unsigned int j = 0; j < 3; j++) {
373 /* Set the channel lut address */
374 c3_isp_write(isp, ISP_PST_GAMMA_LUT_ADDR,
375 ISP_PST_GAMMA_LUT_ADDR_IDX_ADDR(j));
376
377 /* Need to write 2 lut values at once */
378 for (i = 0; i < ARRAY_SIZE(gm->lut) / 2; i++) {
379 base = i * 2;
380 c3_isp_write(isp, ISP_PST_GAMMA_LUT_DATA,
381 ISP_PST_GM_LUT_DATA0(gm->lut[base]) |
382 ISP_PST_GM_LUT_DATA1(gm->lut[base + 1]));
383 }
384
385 /* Write the last one */
386 if (ARRAY_SIZE(gm->lut) % 2) {
387 base = i * 2;
388 c3_isp_write(isp, ISP_PST_GAMMA_LUT_DATA,
389 ISP_PST_GM_LUT_DATA0(gm->lut[base]));
390 }
391 }
392
393 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
394 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
395 ISP_TOP_BED_CTRL_PST_GAMMA_EN_MASK,
396 ISP_TOP_BED_CTRL_PST_GAMMA_EN);
397 }
398
399 /* Configure 3 x 3 ccm matrix */
c3_isp_params_cfg_ccm(struct c3_isp_device * isp,const union c3_isp_params_block * block)400 static void c3_isp_params_cfg_ccm(struct c3_isp_device *isp,
401 const union c3_isp_params_block *block)
402 {
403 const struct c3_isp_params_ccm *ccm = &block->ccm;
404
405 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
406 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
407 ISP_TOP_BED_CTRL_CCM_EN_MASK,
408 ISP_TOP_BED_CTRL_CCM_DIS);
409 return;
410 }
411
412 c3_isp_update_bits(isp, ISP_CCM_MTX_00_01,
413 ISP_CCM_MTX_00_01_MTX_00_MASK,
414 ISP_CCM_MTX_00_01_MTX_00(ccm->matrix[0][0]));
415 c3_isp_update_bits(isp, ISP_CCM_MTX_00_01,
416 ISP_CCM_MTX_00_01_MTX_01_MASK,
417 ISP_CCM_MTX_00_01_MTX_01(ccm->matrix[0][1]));
418 c3_isp_update_bits(isp, ISP_CCM_MTX_02_03,
419 ISP_CCM_MTX_02_03_MTX_02_MASK,
420 ISP_CCM_MTX_02_03_MTX_02(ccm->matrix[0][2]));
421
422 c3_isp_update_bits(isp, ISP_CCM_MTX_10_11,
423 ISP_CCM_MTX_10_11_MTX_10_MASK,
424 ISP_CCM_MTX_10_11_MTX_10(ccm->matrix[1][0]));
425 c3_isp_update_bits(isp, ISP_CCM_MTX_10_11,
426 ISP_CCM_MTX_10_11_MTX_11_MASK,
427 ISP_CCM_MTX_10_11_MTX_11(ccm->matrix[1][1]));
428 c3_isp_update_bits(isp, ISP_CCM_MTX_12_13,
429 ISP_CCM_MTX_12_13_MTX_12_MASK,
430 ISP_CCM_MTX_12_13_MTX_12(ccm->matrix[1][2]));
431
432 c3_isp_update_bits(isp, ISP_CCM_MTX_20_21,
433 ISP_CCM_MTX_20_21_MTX_20_MASK,
434 ISP_CCM_MTX_20_21_MTX_20(ccm->matrix[2][0]));
435 c3_isp_update_bits(isp, ISP_CCM_MTX_20_21,
436 ISP_CCM_MTX_20_21_MTX_21_MASK,
437 ISP_CCM_MTX_20_21_MTX_21(ccm->matrix[2][1]));
438 c3_isp_update_bits(isp, ISP_CCM_MTX_22_23_RS,
439 ISP_CCM_MTX_22_23_RS_MTX_22_MASK,
440 ISP_CCM_MTX_22_23_RS_MTX_22(ccm->matrix[2][2]));
441
442 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
443 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
444 ISP_TOP_BED_CTRL_CCM_EN_MASK,
445 ISP_TOP_BED_CTRL_CCM_EN);
446 }
447
448 /* Configure color space conversion matrix parameters */
c3_isp_params_cfg_csc(struct c3_isp_device * isp,const union c3_isp_params_block * block)449 static void c3_isp_params_cfg_csc(struct c3_isp_device *isp,
450 const union c3_isp_params_block *block)
451 {
452 const struct c3_isp_params_csc *csc = &block->csc;
453
454 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
455 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
456 ISP_TOP_BED_CTRL_CM0_EN_MASK,
457 ISP_TOP_BED_CTRL_CM0_DIS);
458 return;
459 }
460
461 c3_isp_update_bits(isp, ISP_CM0_COEF00_01,
462 ISP_CM0_COEF00_01_MTX_00_MASK,
463 ISP_CM0_COEF00_01_MTX_00(csc->matrix[0][0]));
464 c3_isp_update_bits(isp, ISP_CM0_COEF00_01,
465 ISP_CM0_COEF00_01_MTX_01_MASK,
466 ISP_CM0_COEF00_01_MTX_01(csc->matrix[0][1]));
467 c3_isp_update_bits(isp, ISP_CM0_COEF02_10,
468 ISP_CM0_COEF02_10_MTX_02_MASK,
469 ISP_CM0_COEF02_10_MTX_02(csc->matrix[0][2]));
470
471 c3_isp_update_bits(isp, ISP_CM0_COEF02_10,
472 ISP_CM0_COEF02_10_MTX_10_MASK,
473 ISP_CM0_COEF02_10_MTX_10(csc->matrix[1][0]));
474 c3_isp_update_bits(isp, ISP_CM0_COEF11_12,
475 ISP_CM0_COEF11_12_MTX_11_MASK,
476 ISP_CM0_COEF11_12_MTX_11(csc->matrix[1][1]));
477 c3_isp_update_bits(isp, ISP_CM0_COEF11_12,
478 ISP_CM0_COEF11_12_MTX_12_MASK,
479 ISP_CM0_COEF11_12_MTX_12(csc->matrix[1][2]));
480
481 c3_isp_update_bits(isp, ISP_CM0_COEF20_21,
482 ISP_CM0_COEF20_21_MTX_20_MASK,
483 ISP_CM0_COEF20_21_MTX_20(csc->matrix[2][0]));
484 c3_isp_update_bits(isp, ISP_CM0_COEF20_21,
485 ISP_CM0_COEF20_21_MTX_21_MASK,
486 ISP_CM0_COEF20_21_MTX_21(csc->matrix[2][1]));
487 c3_isp_update_bits(isp, ISP_CM0_COEF22_OUP_OFST0,
488 ISP_CM0_COEF22_OUP_OFST0_MTX_22_MASK,
489 ISP_CM0_COEF22_OUP_OFST0_MTX_22(csc->matrix[2][2]));
490
491 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
492 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
493 ISP_TOP_BED_CTRL_CM0_EN_MASK,
494 ISP_TOP_BED_CTRL_CM0_EN);
495 }
496
497 /* Set blc offset of each color channel */
c3_isp_params_cfg_blc(struct c3_isp_device * isp,const union c3_isp_params_block * block)498 static void c3_isp_params_cfg_blc(struct c3_isp_device *isp,
499 const union c3_isp_params_block *block)
500 {
501 const struct c3_isp_params_blc *blc = &block->blc;
502
503 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) {
504 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL,
505 ISP_TOP_BEO_CTRL_BLC_EN_MASK,
506 ISP_TOP_BEO_CTRL_BLC_DIS);
507 return;
508 }
509
510 c3_isp_write(isp, ISP_LSWB_BLC_OFST0,
511 ISP_LSWB_BLC_OFST0_R_OFST(blc->r_ofst) |
512 ISP_LSWB_BLC_OFST0_GR_OFST(blc->gr_ofst));
513 c3_isp_write(isp, ISP_LSWB_BLC_OFST1,
514 ISP_LSWB_BLC_OFST1_GB_OFST(blc->gb_ofst) |
515 ISP_LSWB_BLC_OFST1_B_OFST(blc->b_ofst));
516
517 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE)
518 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL,
519 ISP_TOP_BEO_CTRL_BLC_EN_MASK,
520 ISP_TOP_BEO_CTRL_BLC_EN);
521 }
522
523 static const c3_isp_block_handler c3_isp_params_handlers[] = {
524 [C3_ISP_PARAMS_BLOCK_AWB_GAINS] = c3_isp_params_cfg_awb_gains,
525 [C3_ISP_PARAMS_BLOCK_AWB_CONFIG] = c3_isp_params_cfg_awb_config,
526 [C3_ISP_PARAMS_BLOCK_AE_CONFIG] = c3_isp_params_cfg_ae_config,
527 [C3_ISP_PARAMS_BLOCK_AF_CONFIG] = c3_isp_params_cfg_af_config,
528 [C3_ISP_PARAMS_BLOCK_PST_GAMMA] = c3_isp_params_cfg_pst_gamma,
529 [C3_ISP_PARAMS_BLOCK_CCM] = c3_isp_params_cfg_ccm,
530 [C3_ISP_PARAMS_BLOCK_CSC] = c3_isp_params_cfg_csc,
531 [C3_ISP_PARAMS_BLOCK_BLC] = c3_isp_params_cfg_blc,
532 };
533
534 #define C3_ISP_PARAMS_BLOCK_INFO(block, data) \
535 [C3_ISP_PARAMS_BLOCK_ ## block] = { \
536 .size = sizeof(struct c3_isp_params_ ## data), \
537 }
538
539 static const struct v4l2_isp_params_block_type_info
540 c3_isp_params_block_types_info[] = {
541 C3_ISP_PARAMS_BLOCK_INFO(AWB_GAINS, awb_gains),
542 C3_ISP_PARAMS_BLOCK_INFO(AWB_CONFIG, awb_config),
543 C3_ISP_PARAMS_BLOCK_INFO(AE_CONFIG, ae_config),
544 C3_ISP_PARAMS_BLOCK_INFO(AF_CONFIG, af_config),
545 C3_ISP_PARAMS_BLOCK_INFO(PST_GAMMA, pst_gamma),
546 C3_ISP_PARAMS_BLOCK_INFO(CCM, ccm),
547 C3_ISP_PARAMS_BLOCK_INFO(CSC, csc),
548 C3_ISP_PARAMS_BLOCK_INFO(BLC, blc),
549 };
550
551 static_assert(ARRAY_SIZE(c3_isp_params_handlers) ==
552 ARRAY_SIZE(c3_isp_params_block_types_info));
553
c3_isp_params_cfg_blocks(struct c3_isp_params * params)554 static void c3_isp_params_cfg_blocks(struct c3_isp_params *params)
555 {
556 struct c3_isp_params_cfg *config = params->buff->cfg;
557 size_t block_offset = 0;
558
559 if (WARN_ON(!config))
560 return;
561
562 /* Walk the list of parameter blocks and process them */
563 while (block_offset < config->data_size) {
564 const union c3_isp_params_block *block;
565 c3_isp_block_handler block_handler;
566
567 block = (const union c3_isp_params_block *)
568 &config->data[block_offset];
569
570 block_handler = c3_isp_params_handlers[block->header.type];
571 block_handler(params->isp, block);
572
573 block_offset += block->header.size;
574 }
575 }
576
c3_isp_params_pre_cfg(struct c3_isp_device * isp)577 void c3_isp_params_pre_cfg(struct c3_isp_device *isp)
578 {
579 struct c3_isp_params *params = &isp->params;
580
581 /* Disable some unused modules */
582 c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL0,
583 ISP_TOP_FEO_CTRL0_INPUT_FMT_EN_MASK,
584 ISP_TOP_FEO_CTRL0_INPUT_FMT_DIS);
585
586 c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL1_0,
587 ISP_TOP_FEO_CTRL1_0_DPC_EN_MASK,
588 ISP_TOP_FEO_CTRL1_0_DPC_DIS);
589 c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL1_0,
590 ISP_TOP_FEO_CTRL1_0_OG_EN_MASK,
591 ISP_TOP_FEO_CTRL1_0_OG_DIS);
592
593 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_PDPC_EN_MASK,
594 ISP_TOP_FED_CTRL_PDPC_DIS);
595 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL,
596 ISP_TOP_FED_CTRL_RAWCNR_EN_MASK,
597 ISP_TOP_FED_CTRL_RAWCNR_DIS);
598 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_SNR1_EN_MASK,
599 ISP_TOP_FED_CTRL_SNR1_DIS);
600 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_TNR0_EN_MASK,
601 ISP_TOP_FED_CTRL_TNR0_DIS);
602 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL,
603 ISP_TOP_FED_CTRL_CUBIC_CS_EN_MASK,
604 ISP_TOP_FED_CTRL_CUBIC_CS_DIS);
605 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_SQRT_EN_MASK,
606 ISP_TOP_FED_CTRL_SQRT_DIS);
607 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL,
608 ISP_TOP_FED_CTRL_DGAIN_EN_MASK,
609 ISP_TOP_FED_CTRL_DGAIN_DIS);
610
611 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL,
612 ISP_TOP_BEO_CTRL_INV_DGAIN_EN_MASK,
613 ISP_TOP_BEO_CTRL_INV_DGAIN_DIS);
614 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, ISP_TOP_BEO_CTRL_EOTF_EN_MASK,
615 ISP_TOP_BEO_CTRL_EOTF_DIS);
616
617 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
618 ISP_TOP_BED_CTRL_YHS_STAT_EN_MASK,
619 ISP_TOP_BED_CTRL_YHS_STAT_DIS);
620 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
621 ISP_TOP_BED_CTRL_GRPH_STAT_EN_MASK,
622 ISP_TOP_BED_CTRL_GRPH_STAT_DIS);
623 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
624 ISP_TOP_BED_CTRL_FMETER_EN_MASK,
625 ISP_TOP_BED_CTRL_FMETER_DIS);
626 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_BSC_EN_MASK,
627 ISP_TOP_BED_CTRL_BSC_DIS);
628 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_CNR2_EN_MASK,
629 ISP_TOP_BED_CTRL_CNR2_DIS);
630 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_CM1_EN_MASK,
631 ISP_TOP_BED_CTRL_CM1_DIS);
632 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
633 ISP_TOP_BED_CTRL_LUT3D_EN_MASK,
634 ISP_TOP_BED_CTRL_LUT3D_DIS);
635 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL,
636 ISP_TOP_BED_CTRL_PST_TNR_LITE_EN_MASK,
637 ISP_TOP_BED_CTRL_PST_TNR_LITE_DIS);
638 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_AMCM_EN_MASK,
639 ISP_TOP_BED_CTRL_AMCM_DIS);
640
641 /*
642 * Disable AE, AF and AWB stat module. Please configure the parameters
643 * in userspace algorithm if need to enable these switch.
644 */
645 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
646 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK,
647 ISP_TOP_3A_STAT_CRTL_AE_STAT_DIS);
648 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
649 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK,
650 ISP_TOP_3A_STAT_CRTL_AWB_STAT_DIS);
651 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL,
652 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK,
653 ISP_TOP_3A_STAT_CRTL_AF_STAT_DIS);
654
655 c3_isp_write(isp, ISP_LSWB_WB_LIMIT0,
656 ISP_LSWB_WB_LIMIT0_WB_LIMIT_R_MAX |
657 ISP_LSWB_WB_LIMIT0_WB_LIMIT_GR_MAX);
658 c3_isp_write(isp, ISP_LSWB_WB_LIMIT1,
659 ISP_LSWB_WB_LIMIT1_WB_LIMIT_GB_MAX |
660 ISP_LSWB_WB_LIMIT1_WB_LIMIT_B_MAX);
661
662 guard(spinlock_irqsave)(¶ms->buff_lock);
663
664 /* Only use the first buffer to initialize ISP */
665 params->buff =
666 list_first_entry_or_null(¶ms->pending,
667 struct c3_isp_params_buffer, list);
668 if (params->buff)
669 c3_isp_params_cfg_blocks(params);
670 }
671
672 /* V4L2 video operations */
673
c3_isp_params_querycap(struct file * file,void * fh,struct v4l2_capability * cap)674 static int c3_isp_params_querycap(struct file *file, void *fh,
675 struct v4l2_capability *cap)
676 {
677 strscpy(cap->driver, C3_ISP_DRIVER_NAME, sizeof(cap->driver));
678 strscpy(cap->card, "AML C3 ISP", sizeof(cap->card));
679
680 return 0;
681 }
682
c3_isp_params_enum_fmt(struct file * file,void * fh,struct v4l2_fmtdesc * f)683 static int c3_isp_params_enum_fmt(struct file *file, void *fh,
684 struct v4l2_fmtdesc *f)
685 {
686 if (f->index)
687 return -EINVAL;
688
689 f->pixelformat = V4L2_META_FMT_C3ISP_PARAMS;
690
691 return 0;
692 }
693
c3_isp_params_g_fmt(struct file * file,void * fh,struct v4l2_format * f)694 static int c3_isp_params_g_fmt(struct file *file, void *fh,
695 struct v4l2_format *f)
696 {
697 struct c3_isp_params *params = video_drvdata(file);
698
699 f->fmt.meta = params->vfmt.fmt.meta;
700
701 return 0;
702 }
703
704 static const struct v4l2_ioctl_ops isp_params_v4l2_ioctl_ops = {
705 .vidioc_querycap = c3_isp_params_querycap,
706 .vidioc_enum_fmt_meta_out = c3_isp_params_enum_fmt,
707 .vidioc_g_fmt_meta_out = c3_isp_params_g_fmt,
708 .vidioc_s_fmt_meta_out = c3_isp_params_g_fmt,
709 .vidioc_try_fmt_meta_out = c3_isp_params_g_fmt,
710 .vidioc_reqbufs = vb2_ioctl_reqbufs,
711 .vidioc_querybuf = vb2_ioctl_querybuf,
712 .vidioc_qbuf = vb2_ioctl_qbuf,
713 .vidioc_expbuf = vb2_ioctl_expbuf,
714 .vidioc_dqbuf = vb2_ioctl_dqbuf,
715 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
716 .vidioc_create_bufs = vb2_ioctl_create_bufs,
717 .vidioc_streamon = vb2_ioctl_streamon,
718 .vidioc_streamoff = vb2_ioctl_streamoff,
719 };
720
721 static const struct v4l2_file_operations isp_params_v4l2_fops = {
722 .open = v4l2_fh_open,
723 .release = vb2_fop_release,
724 .poll = vb2_fop_poll,
725 .unlocked_ioctl = video_ioctl2,
726 .mmap = vb2_fop_mmap,
727 };
728
c3_isp_params_vb2_queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])729 static int c3_isp_params_vb2_queue_setup(struct vb2_queue *q,
730 unsigned int *num_buffers,
731 unsigned int *num_planes,
732 unsigned int sizes[],
733 struct device *alloc_devs[])
734 {
735 if (*num_planes) {
736 if (*num_planes != 1)
737 return -EINVAL;
738
739 if (sizes[0] < sizeof(struct c3_isp_params_cfg))
740 return -EINVAL;
741
742 return 0;
743 }
744
745 *num_planes = 1;
746 sizes[0] = sizeof(struct c3_isp_params_cfg);
747
748 return 0;
749 }
750
c3_isp_params_vb2_buf_queue(struct vb2_buffer * vb)751 static void c3_isp_params_vb2_buf_queue(struct vb2_buffer *vb)
752 {
753 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
754 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf);
755 struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue);
756
757 guard(spinlock_irqsave)(¶ms->buff_lock);
758
759 list_add_tail(&buf->list, ¶ms->pending);
760 }
761
c3_isp_params_vb2_buf_prepare(struct vb2_buffer * vb)762 static int c3_isp_params_vb2_buf_prepare(struct vb2_buffer *vb)
763 {
764 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
765 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(vbuf);
766 struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue);
767 struct c3_isp_params_cfg *usr_cfg = vb2_plane_vaddr(vb, 0);
768 size_t payload_size = vb2_get_plane_payload(vb, 0);
769 struct c3_isp_params_cfg *cfg = buf->cfg;
770 int ret;
771
772 ret = v4l2_isp_params_validate_buffer_size(params->isp->dev, vb,
773 params->vfmt.fmt.meta.buffersize);
774 if (ret)
775 return ret;
776
777 /*
778 * Use the internal scratch buffer to avoid userspace modifying
779 * the buffer content while the driver is processing it.
780 */
781 memcpy(cfg, usr_cfg, payload_size);
782
783 return v4l2_isp_params_validate_buffer(params->isp->dev, vb,
784 (struct v4l2_isp_params_buffer *)cfg,
785 c3_isp_params_block_types_info,
786 ARRAY_SIZE(c3_isp_params_block_types_info));
787 }
788
c3_isp_params_vb2_buf_init(struct vb2_buffer * vb)789 static int c3_isp_params_vb2_buf_init(struct vb2_buffer *vb)
790 {
791 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
792 struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue);
793 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf);
794
795 buf->cfg = kvmalloc(params->vfmt.fmt.meta.buffersize, GFP_KERNEL);
796 if (!buf->cfg)
797 return -ENOMEM;
798
799 return 0;
800 }
801
c3_isp_params_vb2_buf_cleanup(struct vb2_buffer * vb)802 static void c3_isp_params_vb2_buf_cleanup(struct vb2_buffer *vb)
803 {
804 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
805 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf);
806
807 kvfree(buf->cfg);
808 buf->cfg = NULL;
809 }
810
c3_isp_params_vb2_stop_streaming(struct vb2_queue * q)811 static void c3_isp_params_vb2_stop_streaming(struct vb2_queue *q)
812 {
813 struct c3_isp_params *params = vb2_get_drv_priv(q);
814 struct c3_isp_params_buffer *buff;
815
816 guard(spinlock_irqsave)(¶ms->buff_lock);
817
818 while (!list_empty(¶ms->pending)) {
819 buff = list_first_entry(¶ms->pending,
820 struct c3_isp_params_buffer, list);
821 list_del(&buff->list);
822 vb2_buffer_done(&buff->vb.vb2_buf, VB2_BUF_STATE_ERROR);
823 }
824 }
825
826 static const struct vb2_ops isp_params_vb2_ops = {
827 .queue_setup = c3_isp_params_vb2_queue_setup,
828 .buf_queue = c3_isp_params_vb2_buf_queue,
829 .buf_prepare = c3_isp_params_vb2_buf_prepare,
830 .buf_init = c3_isp_params_vb2_buf_init,
831 .buf_cleanup = c3_isp_params_vb2_buf_cleanup,
832 .stop_streaming = c3_isp_params_vb2_stop_streaming,
833 };
834
c3_isp_params_register(struct c3_isp_device * isp)835 int c3_isp_params_register(struct c3_isp_device *isp)
836 {
837 struct c3_isp_params *params = &isp->params;
838 struct video_device *vdev = ¶ms->vdev;
839 struct vb2_queue *vb2_q = ¶ms->vb2_q;
840 int ret;
841
842 memset(params, 0, sizeof(*params));
843 params->vfmt.fmt.meta.dataformat = V4L2_META_FMT_C3ISP_PARAMS;
844 params->vfmt.fmt.meta.buffersize = sizeof(struct c3_isp_params_cfg);
845 params->isp = isp;
846 INIT_LIST_HEAD(¶ms->pending);
847 spin_lock_init(¶ms->buff_lock);
848 mutex_init(¶ms->lock);
849
850 snprintf(vdev->name, sizeof(vdev->name), "c3-isp-params");
851 vdev->fops = &isp_params_v4l2_fops;
852 vdev->ioctl_ops = &isp_params_v4l2_ioctl_ops;
853 vdev->v4l2_dev = &isp->v4l2_dev;
854 vdev->lock = ¶ms->lock;
855 vdev->minor = -1;
856 vdev->queue = vb2_q;
857 vdev->release = video_device_release_empty;
858 vdev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING;
859 vdev->vfl_dir = VFL_DIR_TX;
860 video_set_drvdata(vdev, params);
861
862 vb2_q->drv_priv = params;
863 vb2_q->mem_ops = &vb2_vmalloc_memops;
864 vb2_q->ops = &isp_params_vb2_ops;
865 vb2_q->type = V4L2_BUF_TYPE_META_OUTPUT;
866 vb2_q->io_modes = VB2_DMABUF | VB2_MMAP;
867 vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
868 vb2_q->buf_struct_size = sizeof(struct c3_isp_params_buffer);
869 vb2_q->dev = isp->dev;
870 vb2_q->lock = ¶ms->lock;
871 vb2_q->min_queued_buffers = 1;
872
873 ret = vb2_queue_init(vb2_q);
874 if (ret)
875 goto err_detroy;
876
877 params->pad.flags = MEDIA_PAD_FL_SOURCE;
878 ret = media_entity_pads_init(&vdev->entity, 1, ¶ms->pad);
879 if (ret)
880 goto err_queue_release;
881
882 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
883 if (ret < 0) {
884 dev_err(isp->dev,
885 "Failed to register %s: %d\n", vdev->name, ret);
886 goto err_entity_cleanup;
887 }
888
889 return 0;
890
891 err_entity_cleanup:
892 media_entity_cleanup(&vdev->entity);
893 err_queue_release:
894 vb2_queue_release(vb2_q);
895 err_detroy:
896 mutex_destroy(¶ms->lock);
897 return ret;
898 }
899
c3_isp_params_unregister(struct c3_isp_device * isp)900 void c3_isp_params_unregister(struct c3_isp_device *isp)
901 {
902 struct c3_isp_params *params = &isp->params;
903
904 vb2_queue_release(¶ms->vb2_q);
905 media_entity_cleanup(¶ms->vdev.entity);
906 video_unregister_device(¶ms->vdev);
907 mutex_destroy(¶ms->lock);
908 }
909
c3_isp_params_isr(struct c3_isp_device * isp)910 void c3_isp_params_isr(struct c3_isp_device *isp)
911 {
912 struct c3_isp_params *params = &isp->params;
913
914 guard(spinlock_irqsave)(¶ms->buff_lock);
915
916 params->buff =
917 list_first_entry_or_null(¶ms->pending,
918 struct c3_isp_params_buffer, list);
919 if (!params->buff)
920 return;
921
922 list_del(¶ms->buff->list);
923
924 c3_isp_params_cfg_blocks(params);
925
926 params->buff->vb.sequence = params->isp->frm_sequence;
927 params->buff->vb.vb2_buf.timestamp = ktime_get();
928 params->buff->vb.field = V4L2_FIELD_NONE;
929 vb2_buffer_done(¶ms->buff->vb.vb2_buf, VB2_BUF_STATE_DONE);
930 }
931