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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c