1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Microchip Image Sensor Controller (ISC) common driver base |
4 | * |
5 | * Copyright (C) 2016-2019 Microchip Technology, Inc. |
6 | * |
7 | * Author: Songjun Wu |
8 | * Author: Eugen Hristev <eugen.hristev@microchip.com> |
9 | * |
10 | */ |
11 | #include <linux/delay.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/math64.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/of_graph.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/pm_runtime.h> |
19 | #include <linux/regmap.h> |
20 | #include <linux/videodev2.h> |
21 | #include <linux/atmel-isc-media.h> |
22 | |
23 | #include <media/v4l2-ctrls.h> |
24 | #include <media/v4l2-device.h> |
25 | #include <media/v4l2-event.h> |
26 | #include <media/v4l2-image-sizes.h> |
27 | #include <media/v4l2-ioctl.h> |
28 | #include <media/v4l2-fwnode.h> |
29 | #include <media/v4l2-subdev.h> |
30 | #include <media/videobuf2-dma-contig.h> |
31 | |
32 | #include "microchip-isc-regs.h" |
33 | #include "microchip-isc.h" |
34 | |
35 | #define ISC_IS_FORMAT_RAW(mbus_code) \ |
36 | (((mbus_code) & 0xf000) == 0x3000) |
37 | |
38 | #define ISC_IS_FORMAT_GREY(mbus_code) \ |
39 | (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \ |
40 | (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8))) |
41 | |
42 | static inline void isc_update_v4l2_ctrls(struct isc_device *isc) |
43 | { |
44 | struct isc_ctrls *ctrls = &isc->ctrls; |
45 | |
46 | /* In here we set the v4l2 controls w.r.t. our pipeline config */ |
47 | v4l2_ctrl_s_ctrl(ctrl: isc->r_gain_ctrl, val: ctrls->gain[ISC_HIS_CFG_MODE_R]); |
48 | v4l2_ctrl_s_ctrl(ctrl: isc->b_gain_ctrl, val: ctrls->gain[ISC_HIS_CFG_MODE_B]); |
49 | v4l2_ctrl_s_ctrl(ctrl: isc->gr_gain_ctrl, val: ctrls->gain[ISC_HIS_CFG_MODE_GR]); |
50 | v4l2_ctrl_s_ctrl(ctrl: isc->gb_gain_ctrl, val: ctrls->gain[ISC_HIS_CFG_MODE_GB]); |
51 | |
52 | v4l2_ctrl_s_ctrl(ctrl: isc->r_off_ctrl, val: ctrls->offset[ISC_HIS_CFG_MODE_R]); |
53 | v4l2_ctrl_s_ctrl(ctrl: isc->b_off_ctrl, val: ctrls->offset[ISC_HIS_CFG_MODE_B]); |
54 | v4l2_ctrl_s_ctrl(ctrl: isc->gr_off_ctrl, val: ctrls->offset[ISC_HIS_CFG_MODE_GR]); |
55 | v4l2_ctrl_s_ctrl(ctrl: isc->gb_off_ctrl, val: ctrls->offset[ISC_HIS_CFG_MODE_GB]); |
56 | } |
57 | |
58 | static inline void isc_update_awb_ctrls(struct isc_device *isc) |
59 | { |
60 | struct isc_ctrls *ctrls = &isc->ctrls; |
61 | |
62 | /* In here we set our actual hw pipeline config */ |
63 | |
64 | regmap_write(map: isc->regmap, ISC_WB_O_RGR, |
65 | val: ((ctrls->offset[ISC_HIS_CFG_MODE_R])) | |
66 | ((ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); |
67 | regmap_write(map: isc->regmap, ISC_WB_O_BGB, |
68 | val: ((ctrls->offset[ISC_HIS_CFG_MODE_B])) | |
69 | ((ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); |
70 | regmap_write(map: isc->regmap, ISC_WB_G_RGR, |
71 | val: ctrls->gain[ISC_HIS_CFG_MODE_R] | |
72 | (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); |
73 | regmap_write(map: isc->regmap, ISC_WB_G_BGB, |
74 | val: ctrls->gain[ISC_HIS_CFG_MODE_B] | |
75 | (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16)); |
76 | } |
77 | |
78 | static inline void isc_reset_awb_ctrls(struct isc_device *isc) |
79 | { |
80 | unsigned int c; |
81 | |
82 | for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { |
83 | /* gains have a fixed point at 9 decimals */ |
84 | isc->ctrls.gain[c] = 1 << 9; |
85 | /* offsets are in 2's complements */ |
86 | isc->ctrls.offset[c] = 0; |
87 | } |
88 | } |
89 | |
90 | static int isc_queue_setup(struct vb2_queue *vq, |
91 | unsigned int *nbuffers, unsigned int *nplanes, |
92 | unsigned int sizes[], struct device *alloc_devs[]) |
93 | { |
94 | struct isc_device *isc = vb2_get_drv_priv(q: vq); |
95 | unsigned int size = isc->fmt.fmt.pix.sizeimage; |
96 | |
97 | if (*nplanes) |
98 | return sizes[0] < size ? -EINVAL : 0; |
99 | |
100 | *nplanes = 1; |
101 | sizes[0] = size; |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | static int isc_buffer_prepare(struct vb2_buffer *vb) |
107 | { |
108 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
109 | struct isc_device *isc = vb2_get_drv_priv(q: vb->vb2_queue); |
110 | unsigned long size = isc->fmt.fmt.pix.sizeimage; |
111 | |
112 | if (vb2_plane_size(vb, plane_no: 0) < size) { |
113 | dev_err(isc->dev, "buffer too small (%lu < %lu)\n" , |
114 | vb2_plane_size(vb, 0), size); |
115 | return -EINVAL; |
116 | } |
117 | |
118 | vb2_set_plane_payload(vb, plane_no: 0, size); |
119 | |
120 | vbuf->field = isc->fmt.fmt.pix.field; |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | static void isc_crop_pfe(struct isc_device *isc) |
126 | { |
127 | struct regmap *regmap = isc->regmap; |
128 | u32 h, w; |
129 | |
130 | h = isc->fmt.fmt.pix.height; |
131 | w = isc->fmt.fmt.pix.width; |
132 | |
133 | /* |
134 | * In case the sensor is not RAW, it will output a pixel (12-16 bits) |
135 | * with two samples on the ISC Data bus (which is 8-12) |
136 | * ISC will count each sample, so, we need to multiply these values |
137 | * by two, to get the real number of samples for the required pixels. |
138 | */ |
139 | if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) { |
140 | h <<= 1; |
141 | w <<= 1; |
142 | } |
143 | |
144 | /* |
145 | * We limit the column/row count that the ISC will output according |
146 | * to the configured resolution that we want. |
147 | * This will avoid the situation where the sensor is misconfigured, |
148 | * sending more data, and the ISC will just take it and DMA to memory, |
149 | * causing corruption. |
150 | */ |
151 | regmap_write(map: regmap, ISC_PFE_CFG1, |
152 | val: (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) | |
153 | (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK)); |
154 | |
155 | regmap_write(map: regmap, ISC_PFE_CFG2, |
156 | val: (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) | |
157 | (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK)); |
158 | |
159 | regmap_update_bits(map: regmap, ISC_PFE_CFG0, |
160 | ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN, |
161 | ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN); |
162 | } |
163 | |
164 | static void isc_start_dma(struct isc_device *isc) |
165 | { |
166 | struct regmap *regmap = isc->regmap; |
167 | u32 sizeimage = isc->fmt.fmt.pix.sizeimage; |
168 | u32 dctrl_dview; |
169 | dma_addr_t addr0; |
170 | |
171 | addr0 = vb2_dma_contig_plane_dma_addr(vb: &isc->cur_frm->vb.vb2_buf, plane_no: 0); |
172 | regmap_write(map: regmap, ISC_DAD0 + isc->offsets.dma, val: addr0); |
173 | |
174 | switch (isc->config.fourcc) { |
175 | case V4L2_PIX_FMT_YUV420: |
176 | regmap_write(map: regmap, ISC_DAD1 + isc->offsets.dma, |
177 | val: addr0 + (sizeimage * 2) / 3); |
178 | regmap_write(map: regmap, ISC_DAD2 + isc->offsets.dma, |
179 | val: addr0 + (sizeimage * 5) / 6); |
180 | break; |
181 | case V4L2_PIX_FMT_YUV422P: |
182 | regmap_write(map: regmap, ISC_DAD1 + isc->offsets.dma, |
183 | val: addr0 + sizeimage / 2); |
184 | regmap_write(map: regmap, ISC_DAD2 + isc->offsets.dma, |
185 | val: addr0 + (sizeimage * 3) / 4); |
186 | break; |
187 | default: |
188 | break; |
189 | } |
190 | |
191 | dctrl_dview = isc->config.dctrl_dview; |
192 | |
193 | regmap_write(map: regmap, ISC_DCTRL + isc->offsets.dma, |
194 | val: dctrl_dview | ISC_DCTRL_IE_IS); |
195 | spin_lock(lock: &isc->awb_lock); |
196 | regmap_write(map: regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); |
197 | spin_unlock(lock: &isc->awb_lock); |
198 | } |
199 | |
200 | static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) |
201 | { |
202 | struct regmap *regmap = isc->regmap; |
203 | struct isc_ctrls *ctrls = &isc->ctrls; |
204 | u32 val, bay_cfg; |
205 | const u32 *gamma; |
206 | unsigned int i; |
207 | |
208 | /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ |
209 | for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { |
210 | val = pipeline & BIT(i) ? 1 : 0; |
211 | regmap_field_write(field: isc->pipeline[i], val); |
212 | } |
213 | |
214 | if (!pipeline) |
215 | return; |
216 | |
217 | bay_cfg = isc->config.sd_format->cfa_baycfg; |
218 | |
219 | regmap_write(map: regmap, ISC_WB_CFG, val: bay_cfg); |
220 | isc_update_awb_ctrls(isc); |
221 | isc_update_v4l2_ctrls(isc); |
222 | |
223 | regmap_write(map: regmap, ISC_CFA_CFG, val: bay_cfg | ISC_CFA_CFG_EITPOL); |
224 | |
225 | gamma = &isc->gamma_table[ctrls->gamma_index][0]; |
226 | regmap_bulk_write(map: regmap, ISC_GAM_BENTRY, val: gamma, GAMMA_ENTRIES); |
227 | regmap_bulk_write(map: regmap, ISC_GAM_GENTRY, val: gamma, GAMMA_ENTRIES); |
228 | regmap_bulk_write(map: regmap, ISC_GAM_RENTRY, val: gamma, GAMMA_ENTRIES); |
229 | |
230 | isc->config_dpc(isc); |
231 | isc->config_csc(isc); |
232 | isc->config_cbc(isc); |
233 | isc->config_cc(isc); |
234 | isc->config_gam(isc); |
235 | } |
236 | |
237 | static int isc_update_profile(struct isc_device *isc) |
238 | { |
239 | struct regmap *regmap = isc->regmap; |
240 | u32 sr; |
241 | int counter = 100; |
242 | |
243 | regmap_write(map: regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); |
244 | |
245 | regmap_read(map: regmap, ISC_CTRLSR, val: &sr); |
246 | while ((sr & ISC_CTRL_UPPRO) && counter--) { |
247 | usleep_range(min: 1000, max: 2000); |
248 | regmap_read(map: regmap, ISC_CTRLSR, val: &sr); |
249 | } |
250 | |
251 | if (counter < 0) { |
252 | v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n" ); |
253 | return -ETIMEDOUT; |
254 | } |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | static void isc_set_histogram(struct isc_device *isc, bool enable) |
260 | { |
261 | struct regmap *regmap = isc->regmap; |
262 | struct isc_ctrls *ctrls = &isc->ctrls; |
263 | |
264 | if (enable) { |
265 | regmap_write(map: regmap, ISC_HIS_CFG + isc->offsets.his, |
266 | ISC_HIS_CFG_MODE_GR | |
267 | (isc->config.sd_format->cfa_baycfg |
268 | << ISC_HIS_CFG_BAYSEL_SHIFT) | |
269 | ISC_HIS_CFG_RAR); |
270 | regmap_write(map: regmap, ISC_HIS_CTRL + isc->offsets.his, |
271 | ISC_HIS_CTRL_EN); |
272 | regmap_write(map: regmap, ISC_INTEN, ISC_INT_HISDONE); |
273 | ctrls->hist_id = ISC_HIS_CFG_MODE_GR; |
274 | isc_update_profile(isc); |
275 | regmap_write(map: regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); |
276 | |
277 | ctrls->hist_stat = HIST_ENABLED; |
278 | } else { |
279 | regmap_write(map: regmap, ISC_INTDIS, ISC_INT_HISDONE); |
280 | regmap_write(map: regmap, ISC_HIS_CTRL + isc->offsets.his, |
281 | ISC_HIS_CTRL_DIS); |
282 | |
283 | ctrls->hist_stat = HIST_DISABLED; |
284 | } |
285 | } |
286 | |
287 | static int isc_configure(struct isc_device *isc) |
288 | { |
289 | struct regmap *regmap = isc->regmap; |
290 | u32 pfe_cfg0, dcfg, mask, pipeline; |
291 | struct isc_subdev_entity *subdev = isc->current_subdev; |
292 | |
293 | pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; |
294 | pipeline = isc->config.bits_pipeline; |
295 | |
296 | dcfg = isc->config.dcfg_imode | isc->dcfg; |
297 | |
298 | pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; |
299 | mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | |
300 | ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | |
301 | ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC | |
302 | ISC_PFE_CFG0_CCIR656 | ISC_PFE_CFG0_MIPI; |
303 | |
304 | regmap_update_bits(map: regmap, ISC_PFE_CFG0, mask, val: pfe_cfg0); |
305 | |
306 | isc->config_rlp(isc); |
307 | |
308 | regmap_write(map: regmap, ISC_DCFG + isc->offsets.dma, val: dcfg); |
309 | |
310 | /* Set the pipeline */ |
311 | isc_set_pipeline(isc, pipeline); |
312 | |
313 | /* |
314 | * The current implemented histogram is available for RAW R, B, GB, GR |
315 | * channels. We need to check if sensor is outputting RAW BAYER |
316 | */ |
317 | if (isc->ctrls.awb && |
318 | ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) |
319 | isc_set_histogram(isc, enable: true); |
320 | else |
321 | isc_set_histogram(isc, enable: false); |
322 | |
323 | /* Update profile */ |
324 | return isc_update_profile(isc); |
325 | } |
326 | |
327 | static int isc_prepare_streaming(struct vb2_queue *vq) |
328 | { |
329 | struct isc_device *isc = vb2_get_drv_priv(q: vq); |
330 | |
331 | return media_pipeline_start(pad: isc->video_dev.entity.pads, pipe: &isc->mpipe); |
332 | } |
333 | |
334 | static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) |
335 | { |
336 | struct isc_device *isc = vb2_get_drv_priv(q: vq); |
337 | struct regmap *regmap = isc->regmap; |
338 | struct isc_buffer *buf; |
339 | unsigned long flags; |
340 | int ret; |
341 | |
342 | /* Enable stream on the sub device */ |
343 | ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); |
344 | if (ret && ret != -ENOIOCTLCMD) { |
345 | dev_err(isc->dev, "stream on failed in subdev %d\n" , ret); |
346 | goto err_start_stream; |
347 | } |
348 | |
349 | ret = pm_runtime_resume_and_get(dev: isc->dev); |
350 | if (ret < 0) { |
351 | dev_err(isc->dev, "RPM resume failed in subdev %d\n" , |
352 | ret); |
353 | goto err_pm_get; |
354 | } |
355 | |
356 | ret = isc_configure(isc); |
357 | if (unlikely(ret)) |
358 | goto err_configure; |
359 | |
360 | /* Enable DMA interrupt */ |
361 | regmap_write(map: regmap, ISC_INTEN, ISC_INT_DDONE); |
362 | |
363 | spin_lock_irqsave(&isc->dma_queue_lock, flags); |
364 | |
365 | isc->sequence = 0; |
366 | isc->stop = false; |
367 | reinit_completion(x: &isc->comp); |
368 | |
369 | isc->cur_frm = list_first_entry(&isc->dma_queue, |
370 | struct isc_buffer, list); |
371 | list_del(entry: &isc->cur_frm->list); |
372 | |
373 | isc_crop_pfe(isc); |
374 | isc_start_dma(isc); |
375 | |
376 | spin_unlock_irqrestore(lock: &isc->dma_queue_lock, flags); |
377 | |
378 | /* if we streaming from RAW, we can do one-shot white balance adj */ |
379 | if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) |
380 | v4l2_ctrl_activate(ctrl: isc->do_wb_ctrl, active: true); |
381 | |
382 | return 0; |
383 | |
384 | err_configure: |
385 | pm_runtime_put_sync(dev: isc->dev); |
386 | err_pm_get: |
387 | v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); |
388 | |
389 | err_start_stream: |
390 | spin_lock_irqsave(&isc->dma_queue_lock, flags); |
391 | list_for_each_entry(buf, &isc->dma_queue, list) |
392 | vb2_buffer_done(vb: &buf->vb.vb2_buf, state: VB2_BUF_STATE_QUEUED); |
393 | INIT_LIST_HEAD(list: &isc->dma_queue); |
394 | spin_unlock_irqrestore(lock: &isc->dma_queue_lock, flags); |
395 | |
396 | return ret; |
397 | } |
398 | |
399 | static void isc_unprepare_streaming(struct vb2_queue *vq) |
400 | { |
401 | struct isc_device *isc = vb2_get_drv_priv(q: vq); |
402 | |
403 | /* Stop media pipeline */ |
404 | media_pipeline_stop(pad: isc->video_dev.entity.pads); |
405 | } |
406 | |
407 | static void isc_stop_streaming(struct vb2_queue *vq) |
408 | { |
409 | struct isc_device *isc = vb2_get_drv_priv(q: vq); |
410 | unsigned long flags; |
411 | struct isc_buffer *buf; |
412 | int ret; |
413 | |
414 | mutex_lock(&isc->awb_mutex); |
415 | v4l2_ctrl_activate(ctrl: isc->do_wb_ctrl, active: false); |
416 | |
417 | isc->stop = true; |
418 | |
419 | /* Wait until the end of the current frame */ |
420 | if (isc->cur_frm && !wait_for_completion_timeout(x: &isc->comp, timeout: 5 * HZ)) |
421 | dev_err(isc->dev, "Timeout waiting for end of the capture\n" ); |
422 | |
423 | mutex_unlock(lock: &isc->awb_mutex); |
424 | |
425 | /* Disable DMA interrupt */ |
426 | regmap_write(map: isc->regmap, ISC_INTDIS, ISC_INT_DDONE); |
427 | |
428 | pm_runtime_put_sync(dev: isc->dev); |
429 | |
430 | /* Disable stream on the sub device */ |
431 | ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); |
432 | if (ret && ret != -ENOIOCTLCMD) |
433 | dev_err(isc->dev, "stream off failed in subdev\n" ); |
434 | |
435 | /* Release all active buffers */ |
436 | spin_lock_irqsave(&isc->dma_queue_lock, flags); |
437 | if (unlikely(isc->cur_frm)) { |
438 | vb2_buffer_done(vb: &isc->cur_frm->vb.vb2_buf, |
439 | state: VB2_BUF_STATE_ERROR); |
440 | isc->cur_frm = NULL; |
441 | } |
442 | list_for_each_entry(buf, &isc->dma_queue, list) |
443 | vb2_buffer_done(vb: &buf->vb.vb2_buf, state: VB2_BUF_STATE_ERROR); |
444 | INIT_LIST_HEAD(list: &isc->dma_queue); |
445 | spin_unlock_irqrestore(lock: &isc->dma_queue_lock, flags); |
446 | } |
447 | |
448 | static void isc_buffer_queue(struct vb2_buffer *vb) |
449 | { |
450 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
451 | struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb); |
452 | struct isc_device *isc = vb2_get_drv_priv(q: vb->vb2_queue); |
453 | unsigned long flags; |
454 | |
455 | spin_lock_irqsave(&isc->dma_queue_lock, flags); |
456 | if (!isc->cur_frm && list_empty(head: &isc->dma_queue) && |
457 | vb2_start_streaming_called(q: vb->vb2_queue)) { |
458 | isc->cur_frm = buf; |
459 | isc_start_dma(isc); |
460 | } else { |
461 | list_add_tail(new: &buf->list, head: &isc->dma_queue); |
462 | } |
463 | spin_unlock_irqrestore(lock: &isc->dma_queue_lock, flags); |
464 | } |
465 | |
466 | static const struct vb2_ops isc_vb2_ops = { |
467 | .queue_setup = isc_queue_setup, |
468 | .wait_prepare = vb2_ops_wait_prepare, |
469 | .wait_finish = vb2_ops_wait_finish, |
470 | .buf_prepare = isc_buffer_prepare, |
471 | .start_streaming = isc_start_streaming, |
472 | .stop_streaming = isc_stop_streaming, |
473 | .buf_queue = isc_buffer_queue, |
474 | .prepare_streaming = isc_prepare_streaming, |
475 | .unprepare_streaming = isc_unprepare_streaming, |
476 | }; |
477 | |
478 | static int isc_querycap(struct file *file, void *priv, |
479 | struct v4l2_capability *cap) |
480 | { |
481 | strscpy(cap->driver, "microchip-isc" , sizeof(cap->driver)); |
482 | strscpy(cap->card, "Microchip Image Sensor Controller" , sizeof(cap->card)); |
483 | |
484 | return 0; |
485 | } |
486 | |
487 | static int isc_enum_fmt_vid_cap(struct file *file, void *priv, |
488 | struct v4l2_fmtdesc *f) |
489 | { |
490 | struct isc_device *isc = video_drvdata(file); |
491 | u32 index = f->index; |
492 | u32 i, supported_index = 0; |
493 | struct isc_format *fmt; |
494 | |
495 | /* |
496 | * If we are not asked a specific mbus_code, we have to report all |
497 | * the formats that we can output. |
498 | */ |
499 | if (!f->mbus_code) { |
500 | if (index >= isc->controller_formats_size) |
501 | return -EINVAL; |
502 | |
503 | f->pixelformat = isc->controller_formats[index].fourcc; |
504 | |
505 | return 0; |
506 | } |
507 | |
508 | /* |
509 | * If a specific mbus_code is requested, check if we support |
510 | * this mbus_code as input for the ISC. |
511 | * If it's supported, then we report the corresponding pixelformat |
512 | * as first possible option for the ISC. |
513 | * E.g. mbus MEDIA_BUS_FMT_YUYV8_2X8 and report |
514 | * 'YUYV' (YUYV 4:2:2) |
515 | */ |
516 | fmt = isc_find_format_by_code(isc, code: f->mbus_code, index: &i); |
517 | if (!fmt) |
518 | return -EINVAL; |
519 | |
520 | if (!index) { |
521 | f->pixelformat = fmt->fourcc; |
522 | |
523 | return 0; |
524 | } |
525 | |
526 | supported_index++; |
527 | |
528 | /* If the index is not raw, we don't have anymore formats to report */ |
529 | if (!ISC_IS_FORMAT_RAW(f->mbus_code)) |
530 | return -EINVAL; |
531 | |
532 | /* |
533 | * We are asked for a specific mbus code, which is raw. |
534 | * We have to search through the formats we can convert to. |
535 | * We have to skip the raw formats, we cannot convert to raw. |
536 | * E.g. 'AR12' (16-bit ARGB 4-4-4-4), 'AR15' (16-bit ARGB 1-5-5-5), etc. |
537 | */ |
538 | for (i = 0; i < isc->controller_formats_size; i++) { |
539 | if (isc->controller_formats[i].raw) |
540 | continue; |
541 | if (index == supported_index) { |
542 | f->pixelformat = isc->controller_formats[i].fourcc; |
543 | return 0; |
544 | } |
545 | supported_index++; |
546 | } |
547 | |
548 | return -EINVAL; |
549 | } |
550 | |
551 | static int isc_g_fmt_vid_cap(struct file *file, void *priv, |
552 | struct v4l2_format *fmt) |
553 | { |
554 | struct isc_device *isc = video_drvdata(file); |
555 | |
556 | *fmt = isc->fmt; |
557 | |
558 | return 0; |
559 | } |
560 | |
561 | /* |
562 | * Checks the current configured format, if ISC can output it, |
563 | * considering which type of format the ISC receives from the sensor |
564 | */ |
565 | static int isc_try_validate_formats(struct isc_device *isc) |
566 | { |
567 | int ret; |
568 | bool bayer = false, yuv = false, rgb = false, grey = false; |
569 | |
570 | /* all formats supported by the RLP module are OK */ |
571 | switch (isc->try_config.fourcc) { |
572 | case V4L2_PIX_FMT_SBGGR8: |
573 | case V4L2_PIX_FMT_SGBRG8: |
574 | case V4L2_PIX_FMT_SGRBG8: |
575 | case V4L2_PIX_FMT_SRGGB8: |
576 | case V4L2_PIX_FMT_SBGGR10: |
577 | case V4L2_PIX_FMT_SGBRG10: |
578 | case V4L2_PIX_FMT_SGRBG10: |
579 | case V4L2_PIX_FMT_SRGGB10: |
580 | case V4L2_PIX_FMT_SBGGR12: |
581 | case V4L2_PIX_FMT_SGBRG12: |
582 | case V4L2_PIX_FMT_SGRBG12: |
583 | case V4L2_PIX_FMT_SRGGB12: |
584 | ret = 0; |
585 | bayer = true; |
586 | break; |
587 | |
588 | case V4L2_PIX_FMT_YUV420: |
589 | case V4L2_PIX_FMT_YUV422P: |
590 | case V4L2_PIX_FMT_YUYV: |
591 | case V4L2_PIX_FMT_UYVY: |
592 | case V4L2_PIX_FMT_VYUY: |
593 | ret = 0; |
594 | yuv = true; |
595 | break; |
596 | |
597 | case V4L2_PIX_FMT_RGB565: |
598 | case V4L2_PIX_FMT_ABGR32: |
599 | case V4L2_PIX_FMT_XBGR32: |
600 | case V4L2_PIX_FMT_ARGB444: |
601 | case V4L2_PIX_FMT_ARGB555: |
602 | ret = 0; |
603 | rgb = true; |
604 | break; |
605 | case V4L2_PIX_FMT_GREY: |
606 | case V4L2_PIX_FMT_Y10: |
607 | case V4L2_PIX_FMT_Y16: |
608 | ret = 0; |
609 | grey = true; |
610 | break; |
611 | default: |
612 | /* any other different formats are not supported */ |
613 | dev_err(isc->dev, "Requested unsupported format.\n" ); |
614 | ret = -EINVAL; |
615 | } |
616 | dev_dbg(isc->dev, |
617 | "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n" , |
618 | rgb, yuv, grey, bayer); |
619 | |
620 | if (bayer && |
621 | !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { |
622 | dev_err(isc->dev, "Cannot output RAW if we do not receive RAW.\n" ); |
623 | return -EINVAL; |
624 | } |
625 | |
626 | if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) && |
627 | !ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) { |
628 | dev_err(isc->dev, "Cannot output GREY if we do not receive RAW/GREY.\n" ); |
629 | return -EINVAL; |
630 | } |
631 | |
632 | if ((rgb || bayer || yuv) && |
633 | ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) { |
634 | dev_err(isc->dev, "Cannot convert GREY to another format.\n" ); |
635 | return -EINVAL; |
636 | } |
637 | |
638 | return ret; |
639 | } |
640 | |
641 | /* |
642 | * Configures the RLP and DMA modules, depending on the output format |
643 | * configured for the ISC. |
644 | * If direct_dump == true, just dump raw data 8/16 bits depending on format. |
645 | */ |
646 | static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump) |
647 | { |
648 | isc->try_config.rlp_cfg_mode = 0; |
649 | |
650 | switch (isc->try_config.fourcc) { |
651 | case V4L2_PIX_FMT_SBGGR8: |
652 | case V4L2_PIX_FMT_SGBRG8: |
653 | case V4L2_PIX_FMT_SGRBG8: |
654 | case V4L2_PIX_FMT_SRGGB8: |
655 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; |
656 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; |
657 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
658 | isc->try_config.bpp = 8; |
659 | isc->try_config.bpp_v4l2 = 8; |
660 | break; |
661 | case V4L2_PIX_FMT_SBGGR10: |
662 | case V4L2_PIX_FMT_SGBRG10: |
663 | case V4L2_PIX_FMT_SGRBG10: |
664 | case V4L2_PIX_FMT_SRGGB10: |
665 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10; |
666 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; |
667 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
668 | isc->try_config.bpp = 16; |
669 | isc->try_config.bpp_v4l2 = 16; |
670 | break; |
671 | case V4L2_PIX_FMT_SBGGR12: |
672 | case V4L2_PIX_FMT_SGBRG12: |
673 | case V4L2_PIX_FMT_SGRBG12: |
674 | case V4L2_PIX_FMT_SRGGB12: |
675 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12; |
676 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; |
677 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
678 | isc->try_config.bpp = 16; |
679 | isc->try_config.bpp_v4l2 = 16; |
680 | break; |
681 | case V4L2_PIX_FMT_RGB565: |
682 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565; |
683 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; |
684 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
685 | isc->try_config.bpp = 16; |
686 | isc->try_config.bpp_v4l2 = 16; |
687 | break; |
688 | case V4L2_PIX_FMT_ARGB444: |
689 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444; |
690 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; |
691 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
692 | isc->try_config.bpp = 16; |
693 | isc->try_config.bpp_v4l2 = 16; |
694 | break; |
695 | case V4L2_PIX_FMT_ARGB555: |
696 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555; |
697 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; |
698 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
699 | isc->try_config.bpp = 16; |
700 | isc->try_config.bpp_v4l2 = 16; |
701 | break; |
702 | case V4L2_PIX_FMT_ABGR32: |
703 | case V4L2_PIX_FMT_XBGR32: |
704 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32; |
705 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; |
706 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
707 | isc->try_config.bpp = 32; |
708 | isc->try_config.bpp_v4l2 = 32; |
709 | break; |
710 | case V4L2_PIX_FMT_YUV420: |
711 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; |
712 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P; |
713 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; |
714 | isc->try_config.bpp = 12; |
715 | isc->try_config.bpp_v4l2 = 8; /* only first plane */ |
716 | break; |
717 | case V4L2_PIX_FMT_YUV422P: |
718 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; |
719 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P; |
720 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; |
721 | isc->try_config.bpp = 16; |
722 | isc->try_config.bpp_v4l2 = 8; /* only first plane */ |
723 | break; |
724 | case V4L2_PIX_FMT_YUYV: |
725 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_YUYV; |
726 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; |
727 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
728 | isc->try_config.bpp = 16; |
729 | isc->try_config.bpp_v4l2 = 16; |
730 | break; |
731 | case V4L2_PIX_FMT_UYVY: |
732 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_UYVY; |
733 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; |
734 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
735 | isc->try_config.bpp = 16; |
736 | isc->try_config.bpp_v4l2 = 16; |
737 | break; |
738 | case V4L2_PIX_FMT_VYUY: |
739 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_VYUY; |
740 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; |
741 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
742 | isc->try_config.bpp = 16; |
743 | isc->try_config.bpp_v4l2 = 16; |
744 | break; |
745 | case V4L2_PIX_FMT_GREY: |
746 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8; |
747 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; |
748 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
749 | isc->try_config.bpp = 8; |
750 | isc->try_config.bpp_v4l2 = 8; |
751 | break; |
752 | case V4L2_PIX_FMT_Y16: |
753 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10 | ISC_RLP_CFG_LSH; |
754 | fallthrough; |
755 | case V4L2_PIX_FMT_Y10: |
756 | isc->try_config.rlp_cfg_mode |= ISC_RLP_CFG_MODE_DATY10; |
757 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; |
758 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
759 | isc->try_config.bpp = 16; |
760 | isc->try_config.bpp_v4l2 = 16; |
761 | break; |
762 | default: |
763 | return -EINVAL; |
764 | } |
765 | |
766 | if (direct_dump) { |
767 | isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; |
768 | isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; |
769 | isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; |
770 | return 0; |
771 | } |
772 | |
773 | return 0; |
774 | } |
775 | |
776 | /* |
777 | * Configuring pipeline modules, depending on which format the ISC outputs |
778 | * and considering which format it has as input from the sensor. |
779 | */ |
780 | static int isc_try_configure_pipeline(struct isc_device *isc) |
781 | { |
782 | switch (isc->try_config.fourcc) { |
783 | case V4L2_PIX_FMT_RGB565: |
784 | case V4L2_PIX_FMT_ARGB555: |
785 | case V4L2_PIX_FMT_ARGB444: |
786 | case V4L2_PIX_FMT_ABGR32: |
787 | case V4L2_PIX_FMT_XBGR32: |
788 | /* if sensor format is RAW, we convert inside ISC */ |
789 | if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { |
790 | isc->try_config.bits_pipeline = CFA_ENABLE | |
791 | WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE | |
792 | CC_ENABLE; |
793 | } else { |
794 | isc->try_config.bits_pipeline = 0x0; |
795 | } |
796 | break; |
797 | case V4L2_PIX_FMT_YUV420: |
798 | /* if sensor format is RAW, we convert inside ISC */ |
799 | if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { |
800 | isc->try_config.bits_pipeline = CFA_ENABLE | |
801 | CSC_ENABLE | GAM_ENABLES | WB_ENABLE | |
802 | SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE | |
803 | DPC_BLCENABLE; |
804 | } else { |
805 | isc->try_config.bits_pipeline = 0x0; |
806 | } |
807 | break; |
808 | case V4L2_PIX_FMT_YUV422P: |
809 | /* if sensor format is RAW, we convert inside ISC */ |
810 | if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { |
811 | isc->try_config.bits_pipeline = CFA_ENABLE | |
812 | CSC_ENABLE | WB_ENABLE | GAM_ENABLES | |
813 | SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE; |
814 | } else { |
815 | isc->try_config.bits_pipeline = 0x0; |
816 | } |
817 | break; |
818 | case V4L2_PIX_FMT_YUYV: |
819 | case V4L2_PIX_FMT_UYVY: |
820 | case V4L2_PIX_FMT_VYUY: |
821 | /* if sensor format is RAW, we convert inside ISC */ |
822 | if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { |
823 | isc->try_config.bits_pipeline = CFA_ENABLE | |
824 | CSC_ENABLE | WB_ENABLE | GAM_ENABLES | |
825 | SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE; |
826 | } else { |
827 | isc->try_config.bits_pipeline = 0x0; |
828 | } |
829 | break; |
830 | case V4L2_PIX_FMT_GREY: |
831 | case V4L2_PIX_FMT_Y16: |
832 | /* if sensor format is RAW, we convert inside ISC */ |
833 | if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { |
834 | isc->try_config.bits_pipeline = CFA_ENABLE | |
835 | CSC_ENABLE | WB_ENABLE | GAM_ENABLES | |
836 | CBC_ENABLE | DPC_BLCENABLE; |
837 | } else { |
838 | isc->try_config.bits_pipeline = 0x0; |
839 | } |
840 | break; |
841 | default: |
842 | if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) |
843 | isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE; |
844 | else |
845 | isc->try_config.bits_pipeline = 0x0; |
846 | } |
847 | |
848 | /* Tune the pipeline to product specific */ |
849 | isc->adapt_pipeline(isc); |
850 | |
851 | return 0; |
852 | } |
853 | |
854 | static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f) |
855 | { |
856 | struct v4l2_pix_format *pixfmt = &f->fmt.pix; |
857 | unsigned int i; |
858 | |
859 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
860 | return -EINVAL; |
861 | |
862 | isc->try_config.fourcc = isc->controller_formats[0].fourcc; |
863 | |
864 | /* find if the format requested is supported */ |
865 | for (i = 0; i < isc->controller_formats_size; i++) |
866 | if (isc->controller_formats[i].fourcc == pixfmt->pixelformat) { |
867 | isc->try_config.fourcc = pixfmt->pixelformat; |
868 | break; |
869 | } |
870 | |
871 | isc_try_configure_rlp_dma(isc, direct_dump: false); |
872 | |
873 | /* Limit to Microchip ISC hardware capabilities */ |
874 | v4l_bound_align_image(width: &pixfmt->width, wmin: 16, wmax: isc->max_width, walign: 0, |
875 | height: &pixfmt->height, hmin: 16, hmax: isc->max_height, halign: 0, salign: 0); |
876 | /* If we did not find the requested format, we will fallback here */ |
877 | pixfmt->pixelformat = isc->try_config.fourcc; |
878 | pixfmt->colorspace = V4L2_COLORSPACE_SRGB; |
879 | pixfmt->field = V4L2_FIELD_NONE; |
880 | |
881 | pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp_v4l2) >> 3; |
882 | pixfmt->sizeimage = ((pixfmt->width * isc->try_config.bpp) >> 3) * |
883 | pixfmt->height; |
884 | |
885 | isc->try_fmt = *f; |
886 | |
887 | return 0; |
888 | } |
889 | |
890 | static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) |
891 | { |
892 | isc_try_fmt(isc, f); |
893 | |
894 | /* make the try configuration active */ |
895 | isc->config = isc->try_config; |
896 | isc->fmt = isc->try_fmt; |
897 | |
898 | dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n" , |
899 | (char *)&f->fmt.pix.pixelformat, |
900 | f->fmt.pix.width, f->fmt.pix.height); |
901 | |
902 | return 0; |
903 | } |
904 | |
905 | static int isc_validate(struct isc_device *isc) |
906 | { |
907 | int ret; |
908 | int i; |
909 | struct isc_format *sd_fmt = NULL; |
910 | struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix; |
911 | struct v4l2_subdev_format format = { |
912 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
913 | .pad = isc->remote_pad, |
914 | }; |
915 | |
916 | /* Get current format from subdev */ |
917 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, get_fmt, NULL, |
918 | &format); |
919 | if (ret) |
920 | return ret; |
921 | |
922 | /* Identify the subdev's format configuration */ |
923 | for (i = 0; i < isc->formats_list_size; i++) |
924 | if (isc->formats_list[i].mbus_code == format.format.code) { |
925 | sd_fmt = &isc->formats_list[i]; |
926 | break; |
927 | } |
928 | |
929 | /* Check if the format is not supported */ |
930 | if (!sd_fmt) { |
931 | dev_err(isc->dev, |
932 | "Current subdevice is streaming a media bus code that is not supported 0x%x\n" , |
933 | format.format.code); |
934 | return -EPIPE; |
935 | } |
936 | |
937 | /* At this moment we know which format the subdev will use */ |
938 | isc->try_config.sd_format = sd_fmt; |
939 | |
940 | /* If the sensor is not RAW, we can only do a direct dump */ |
941 | if (!ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) |
942 | isc_try_configure_rlp_dma(isc, direct_dump: true); |
943 | |
944 | /* Limit to Microchip ISC hardware capabilities */ |
945 | v4l_bound_align_image(width: &format.format.width, wmin: 16, wmax: isc->max_width, walign: 0, |
946 | height: &format.format.height, hmin: 16, hmax: isc->max_height, halign: 0, salign: 0); |
947 | |
948 | /* Check if the frame size is the same. Otherwise we may overflow */ |
949 | if (pixfmt->height != format.format.height || |
950 | pixfmt->width != format.format.width) { |
951 | dev_err(isc->dev, |
952 | "ISC not configured with the proper frame size: %dx%d\n" , |
953 | format.format.width, format.format.height); |
954 | return -EPIPE; |
955 | } |
956 | |
957 | dev_dbg(isc->dev, |
958 | "Identified subdev using format %.4s with %dx%d %d bpp\n" , |
959 | (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height, |
960 | isc->try_config.bpp); |
961 | |
962 | /* Reset and restart AWB if the subdevice changed the format */ |
963 | if (isc->try_config.sd_format && isc->config.sd_format && |
964 | isc->try_config.sd_format != isc->config.sd_format) { |
965 | isc->ctrls.hist_stat = HIST_INIT; |
966 | isc_reset_awb_ctrls(isc); |
967 | isc_update_v4l2_ctrls(isc); |
968 | } |
969 | |
970 | /* Validate formats */ |
971 | ret = isc_try_validate_formats(isc); |
972 | if (ret) |
973 | return ret; |
974 | |
975 | /* Configure ISC pipeline for the config */ |
976 | ret = isc_try_configure_pipeline(isc); |
977 | if (ret) |
978 | return ret; |
979 | |
980 | isc->config = isc->try_config; |
981 | |
982 | dev_dbg(isc->dev, "New ISC configuration in place\n" ); |
983 | |
984 | return 0; |
985 | } |
986 | |
987 | static int isc_s_fmt_vid_cap(struct file *file, void *priv, |
988 | struct v4l2_format *f) |
989 | { |
990 | struct isc_device *isc = video_drvdata(file); |
991 | |
992 | if (vb2_is_busy(q: &isc->vb2_vidq)) |
993 | return -EBUSY; |
994 | |
995 | return isc_set_fmt(isc, f); |
996 | } |
997 | |
998 | static int isc_try_fmt_vid_cap(struct file *file, void *priv, |
999 | struct v4l2_format *f) |
1000 | { |
1001 | struct isc_device *isc = video_drvdata(file); |
1002 | |
1003 | return isc_try_fmt(isc, f); |
1004 | } |
1005 | |
1006 | static int isc_enum_input(struct file *file, void *priv, |
1007 | struct v4l2_input *inp) |
1008 | { |
1009 | if (inp->index != 0) |
1010 | return -EINVAL; |
1011 | |
1012 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
1013 | inp->std = 0; |
1014 | strscpy(inp->name, "Camera" , sizeof(inp->name)); |
1015 | |
1016 | return 0; |
1017 | } |
1018 | |
1019 | static int isc_g_input(struct file *file, void *priv, unsigned int *i) |
1020 | { |
1021 | *i = 0; |
1022 | |
1023 | return 0; |
1024 | } |
1025 | |
1026 | static int isc_s_input(struct file *file, void *priv, unsigned int i) |
1027 | { |
1028 | if (i > 0) |
1029 | return -EINVAL; |
1030 | |
1031 | return 0; |
1032 | } |
1033 | |
1034 | static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) |
1035 | { |
1036 | struct isc_device *isc = video_drvdata(file); |
1037 | |
1038 | return v4l2_g_parm_cap(vdev: video_devdata(file), sd: isc->current_subdev->sd, a); |
1039 | } |
1040 | |
1041 | static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) |
1042 | { |
1043 | struct isc_device *isc = video_drvdata(file); |
1044 | |
1045 | return v4l2_s_parm_cap(vdev: video_devdata(file), sd: isc->current_subdev->sd, a); |
1046 | } |
1047 | |
1048 | static int isc_enum_framesizes(struct file *file, void *fh, |
1049 | struct v4l2_frmsizeenum *fsize) |
1050 | { |
1051 | struct isc_device *isc = video_drvdata(file); |
1052 | int ret = -EINVAL; |
1053 | int i; |
1054 | |
1055 | if (fsize->index) |
1056 | return -EINVAL; |
1057 | |
1058 | for (i = 0; i < isc->controller_formats_size; i++) |
1059 | if (isc->controller_formats[i].fourcc == fsize->pixel_format) |
1060 | ret = 0; |
1061 | |
1062 | if (ret) |
1063 | return ret; |
1064 | |
1065 | fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; |
1066 | |
1067 | fsize->stepwise.min_width = 16; |
1068 | fsize->stepwise.max_width = isc->max_width; |
1069 | fsize->stepwise.min_height = 16; |
1070 | fsize->stepwise.max_height = isc->max_height; |
1071 | fsize->stepwise.step_width = 1; |
1072 | fsize->stepwise.step_height = 1; |
1073 | |
1074 | return 0; |
1075 | } |
1076 | |
1077 | static const struct v4l2_ioctl_ops isc_ioctl_ops = { |
1078 | .vidioc_querycap = isc_querycap, |
1079 | .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap, |
1080 | .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap, |
1081 | .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap, |
1082 | .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap, |
1083 | |
1084 | .vidioc_enum_input = isc_enum_input, |
1085 | .vidioc_g_input = isc_g_input, |
1086 | .vidioc_s_input = isc_s_input, |
1087 | |
1088 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
1089 | .vidioc_querybuf = vb2_ioctl_querybuf, |
1090 | .vidioc_qbuf = vb2_ioctl_qbuf, |
1091 | .vidioc_expbuf = vb2_ioctl_expbuf, |
1092 | .vidioc_dqbuf = vb2_ioctl_dqbuf, |
1093 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
1094 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
1095 | .vidioc_streamon = vb2_ioctl_streamon, |
1096 | .vidioc_streamoff = vb2_ioctl_streamoff, |
1097 | |
1098 | .vidioc_g_parm = isc_g_parm, |
1099 | .vidioc_s_parm = isc_s_parm, |
1100 | .vidioc_enum_framesizes = isc_enum_framesizes, |
1101 | |
1102 | .vidioc_log_status = v4l2_ctrl_log_status, |
1103 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
1104 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
1105 | }; |
1106 | |
1107 | static int isc_open(struct file *file) |
1108 | { |
1109 | struct isc_device *isc = video_drvdata(file); |
1110 | struct v4l2_subdev *sd = isc->current_subdev->sd; |
1111 | int ret; |
1112 | |
1113 | if (mutex_lock_interruptible(&isc->lock)) |
1114 | return -ERESTARTSYS; |
1115 | |
1116 | ret = v4l2_fh_open(filp: file); |
1117 | if (ret < 0) |
1118 | goto unlock; |
1119 | |
1120 | if (!v4l2_fh_is_singular_file(filp: file)) |
1121 | goto unlock; |
1122 | |
1123 | ret = v4l2_subdev_call(sd, core, s_power, 1); |
1124 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
1125 | v4l2_fh_release(filp: file); |
1126 | goto unlock; |
1127 | } |
1128 | |
1129 | ret = isc_set_fmt(isc, f: &isc->fmt); |
1130 | if (ret) { |
1131 | v4l2_subdev_call(sd, core, s_power, 0); |
1132 | v4l2_fh_release(filp: file); |
1133 | } |
1134 | |
1135 | unlock: |
1136 | mutex_unlock(lock: &isc->lock); |
1137 | return ret; |
1138 | } |
1139 | |
1140 | static int isc_release(struct file *file) |
1141 | { |
1142 | struct isc_device *isc = video_drvdata(file); |
1143 | struct v4l2_subdev *sd = isc->current_subdev->sd; |
1144 | bool fh_singular; |
1145 | int ret; |
1146 | |
1147 | mutex_lock(&isc->lock); |
1148 | |
1149 | fh_singular = v4l2_fh_is_singular_file(filp: file); |
1150 | |
1151 | ret = _vb2_fop_release(file, NULL); |
1152 | |
1153 | if (fh_singular) |
1154 | v4l2_subdev_call(sd, core, s_power, 0); |
1155 | |
1156 | mutex_unlock(lock: &isc->lock); |
1157 | |
1158 | return ret; |
1159 | } |
1160 | |
1161 | static const struct v4l2_file_operations isc_fops = { |
1162 | .owner = THIS_MODULE, |
1163 | .open = isc_open, |
1164 | .release = isc_release, |
1165 | .unlocked_ioctl = video_ioctl2, |
1166 | .read = vb2_fop_read, |
1167 | .mmap = vb2_fop_mmap, |
1168 | .poll = vb2_fop_poll, |
1169 | }; |
1170 | |
1171 | irqreturn_t microchip_isc_interrupt(int irq, void *dev_id) |
1172 | { |
1173 | struct isc_device *isc = (struct isc_device *)dev_id; |
1174 | struct regmap *regmap = isc->regmap; |
1175 | u32 isc_intsr, isc_intmask, pending; |
1176 | irqreturn_t ret = IRQ_NONE; |
1177 | |
1178 | regmap_read(map: regmap, ISC_INTSR, val: &isc_intsr); |
1179 | regmap_read(map: regmap, ISC_INTMASK, val: &isc_intmask); |
1180 | |
1181 | pending = isc_intsr & isc_intmask; |
1182 | |
1183 | if (likely(pending & ISC_INT_DDONE)) { |
1184 | spin_lock(lock: &isc->dma_queue_lock); |
1185 | if (isc->cur_frm) { |
1186 | struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; |
1187 | struct vb2_buffer *vb = &vbuf->vb2_buf; |
1188 | |
1189 | vb->timestamp = ktime_get_ns(); |
1190 | vbuf->sequence = isc->sequence++; |
1191 | vb2_buffer_done(vb, state: VB2_BUF_STATE_DONE); |
1192 | isc->cur_frm = NULL; |
1193 | } |
1194 | |
1195 | if (!list_empty(head: &isc->dma_queue) && !isc->stop) { |
1196 | isc->cur_frm = list_first_entry(&isc->dma_queue, |
1197 | struct isc_buffer, list); |
1198 | list_del(entry: &isc->cur_frm->list); |
1199 | |
1200 | isc_start_dma(isc); |
1201 | } |
1202 | |
1203 | if (isc->stop) |
1204 | complete(&isc->comp); |
1205 | |
1206 | ret = IRQ_HANDLED; |
1207 | spin_unlock(lock: &isc->dma_queue_lock); |
1208 | } |
1209 | |
1210 | if (pending & ISC_INT_HISDONE) { |
1211 | schedule_work(work: &isc->awb_work); |
1212 | ret = IRQ_HANDLED; |
1213 | } |
1214 | |
1215 | return ret; |
1216 | } |
1217 | EXPORT_SYMBOL_GPL(microchip_isc_interrupt); |
1218 | |
1219 | static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) |
1220 | { |
1221 | struct regmap *regmap = isc->regmap; |
1222 | struct isc_ctrls *ctrls = &isc->ctrls; |
1223 | u32 *hist_count = &ctrls->hist_count[ctrls->hist_id]; |
1224 | u32 *hist_entry = &ctrls->hist_entry[0]; |
1225 | u32 i; |
1226 | |
1227 | *min = 0; |
1228 | *max = HIST_ENTRIES; |
1229 | |
1230 | regmap_bulk_read(map: regmap, ISC_HIS_ENTRY + isc->offsets.his_entry, |
1231 | val: hist_entry, HIST_ENTRIES); |
1232 | |
1233 | *hist_count = 0; |
1234 | /* |
1235 | * we deliberately ignore the end of the histogram, |
1236 | * the most white pixels |
1237 | */ |
1238 | for (i = 1; i < HIST_ENTRIES; i++) { |
1239 | if (*hist_entry && !*min) |
1240 | *min = i; |
1241 | if (*hist_entry) |
1242 | *max = i; |
1243 | *hist_count += i * (*hist_entry++); |
1244 | } |
1245 | |
1246 | if (!*min) |
1247 | *min = 1; |
1248 | |
1249 | dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u" , |
1250 | ctrls->hist_id, *hist_count); |
1251 | } |
1252 | |
1253 | static void isc_wb_update(struct isc_ctrls *ctrls) |
1254 | { |
1255 | struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls); |
1256 | u32 *hist_count = &ctrls->hist_count[0]; |
1257 | u32 c, offset[4]; |
1258 | u64 avg = 0; |
1259 | /* We compute two gains, stretch gain and grey world gain */ |
1260 | u32 s_gain[4], gw_gain[4]; |
1261 | |
1262 | /* |
1263 | * According to Grey World, we need to set gains for R/B to normalize |
1264 | * them towards the green channel. |
1265 | * Thus we want to keep Green as fixed and adjust only Red/Blue |
1266 | * Compute the average of the both green channels first |
1267 | */ |
1268 | avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] + |
1269 | (u64)hist_count[ISC_HIS_CFG_MODE_GB]; |
1270 | avg >>= 1; |
1271 | |
1272 | dev_dbg(isc->dev, "isc wb: green components average %llu\n" , avg); |
1273 | |
1274 | /* Green histogram is null, nothing to do */ |
1275 | if (!avg) |
1276 | return; |
1277 | |
1278 | for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { |
1279 | /* |
1280 | * the color offset is the minimum value of the histogram. |
1281 | * we stretch this color to the full range by substracting |
1282 | * this value from the color component. |
1283 | */ |
1284 | offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX]; |
1285 | /* |
1286 | * The offset is always at least 1. If the offset is 1, we do |
1287 | * not need to adjust it, so our result must be zero. |
1288 | * the offset is computed in a histogram on 9 bits (0..512) |
1289 | * but the offset in register is based on |
1290 | * 12 bits pipeline (0..4096). |
1291 | * we need to shift with the 3 bits that the histogram is |
1292 | * ignoring |
1293 | */ |
1294 | ctrls->offset[c] = (offset[c] - 1) << 3; |
1295 | |
1296 | /* |
1297 | * the offset is then taken and converted to 2's complements, |
1298 | * and must be negative, as we subtract this value from the |
1299 | * color components |
1300 | */ |
1301 | ctrls->offset[c] = -ctrls->offset[c]; |
1302 | |
1303 | /* |
1304 | * the stretch gain is the total number of histogram bins |
1305 | * divided by the actual range of color component (Max - Min) |
1306 | * If we compute gain like this, the actual color component |
1307 | * will be stretched to the full histogram. |
1308 | * We need to shift 9 bits for precision, we have 9 bits for |
1309 | * decimals |
1310 | */ |
1311 | s_gain[c] = (HIST_ENTRIES << 9) / |
1312 | (ctrls->hist_minmax[c][HIST_MAX_INDEX] - |
1313 | ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1); |
1314 | |
1315 | /* |
1316 | * Now we have to compute the gain w.r.t. the average. |
1317 | * Add/lose gain to the component towards the average. |
1318 | * If it happens that the component is zero, use the |
1319 | * fixed point value : 1.0 gain. |
1320 | */ |
1321 | if (hist_count[c]) |
1322 | gw_gain[c] = div_u64(dividend: avg << 9, divisor: hist_count[c]); |
1323 | else |
1324 | gw_gain[c] = 1 << 9; |
1325 | |
1326 | dev_dbg(isc->dev, |
1327 | "isc wb: component %d, s_gain %u, gw_gain %u\n" , |
1328 | c, s_gain[c], gw_gain[c]); |
1329 | /* multiply both gains and adjust for decimals */ |
1330 | ctrls->gain[c] = s_gain[c] * gw_gain[c]; |
1331 | ctrls->gain[c] >>= 9; |
1332 | |
1333 | /* make sure we are not out of range */ |
1334 | ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0)); |
1335 | |
1336 | dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n" , |
1337 | c, ctrls->gain[c]); |
1338 | } |
1339 | } |
1340 | |
1341 | static void isc_awb_work(struct work_struct *w) |
1342 | { |
1343 | struct isc_device *isc = |
1344 | container_of(w, struct isc_device, awb_work); |
1345 | struct regmap *regmap = isc->regmap; |
1346 | struct isc_ctrls *ctrls = &isc->ctrls; |
1347 | u32 hist_id = ctrls->hist_id; |
1348 | u32 baysel; |
1349 | unsigned long flags; |
1350 | u32 min, max; |
1351 | int ret; |
1352 | |
1353 | if (ctrls->hist_stat != HIST_ENABLED) |
1354 | return; |
1355 | |
1356 | isc_hist_count(isc, min: &min, max: &max); |
1357 | |
1358 | dev_dbg(isc->dev, |
1359 | "isc wb mode %d: hist min %u , max %u\n" , hist_id, min, max); |
1360 | |
1361 | ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; |
1362 | ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; |
1363 | |
1364 | if (hist_id != ISC_HIS_CFG_MODE_B) { |
1365 | hist_id++; |
1366 | } else { |
1367 | isc_wb_update(ctrls); |
1368 | hist_id = ISC_HIS_CFG_MODE_GR; |
1369 | } |
1370 | |
1371 | ctrls->hist_id = hist_id; |
1372 | baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; |
1373 | |
1374 | ret = pm_runtime_resume_and_get(dev: isc->dev); |
1375 | if (ret < 0) |
1376 | return; |
1377 | |
1378 | /* |
1379 | * only update if we have all the required histograms and controls |
1380 | * if awb has been disabled, we need to reset registers as well. |
1381 | */ |
1382 | if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) { |
1383 | /* |
1384 | * It may happen that DMA Done IRQ will trigger while we are |
1385 | * updating white balance registers here. |
1386 | * In that case, only parts of the controls have been updated. |
1387 | * We can avoid that by locking the section. |
1388 | */ |
1389 | spin_lock_irqsave(&isc->awb_lock, flags); |
1390 | isc_update_awb_ctrls(isc); |
1391 | spin_unlock_irqrestore(lock: &isc->awb_lock, flags); |
1392 | |
1393 | /* |
1394 | * if we are doing just the one time white balance adjustment, |
1395 | * we are basically done. |
1396 | */ |
1397 | if (ctrls->awb == ISC_WB_ONETIME) { |
1398 | dev_info(isc->dev, |
1399 | "Completed one time white-balance adjustment.\n" ); |
1400 | /* update the v4l2 controls values */ |
1401 | isc_update_v4l2_ctrls(isc); |
1402 | ctrls->awb = ISC_WB_NONE; |
1403 | } |
1404 | } |
1405 | regmap_write(map: regmap, ISC_HIS_CFG + isc->offsets.his, |
1406 | val: hist_id | baysel | ISC_HIS_CFG_RAR); |
1407 | |
1408 | /* |
1409 | * We have to make sure the streaming has not stopped meanwhile. |
1410 | * ISC requires a frame to clock the internal profile update. |
1411 | * To avoid issues, lock the sequence with a mutex |
1412 | */ |
1413 | mutex_lock(&isc->awb_mutex); |
1414 | |
1415 | /* streaming is not active anymore */ |
1416 | if (isc->stop) { |
1417 | mutex_unlock(lock: &isc->awb_mutex); |
1418 | return; |
1419 | } |
1420 | |
1421 | isc_update_profile(isc); |
1422 | |
1423 | mutex_unlock(lock: &isc->awb_mutex); |
1424 | |
1425 | /* if awb has been disabled, we don't need to start another histogram */ |
1426 | if (ctrls->awb) |
1427 | regmap_write(map: regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); |
1428 | |
1429 | pm_runtime_put_sync(dev: isc->dev); |
1430 | } |
1431 | |
1432 | static int isc_s_ctrl(struct v4l2_ctrl *ctrl) |
1433 | { |
1434 | struct isc_device *isc = container_of(ctrl->handler, |
1435 | struct isc_device, ctrls.handler); |
1436 | struct isc_ctrls *ctrls = &isc->ctrls; |
1437 | |
1438 | if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) |
1439 | return 0; |
1440 | |
1441 | switch (ctrl->id) { |
1442 | case V4L2_CID_BRIGHTNESS: |
1443 | ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; |
1444 | break; |
1445 | case V4L2_CID_CONTRAST: |
1446 | ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK; |
1447 | break; |
1448 | case V4L2_CID_GAMMA: |
1449 | ctrls->gamma_index = ctrl->val; |
1450 | break; |
1451 | default: |
1452 | return -EINVAL; |
1453 | } |
1454 | |
1455 | return 0; |
1456 | } |
1457 | |
1458 | static const struct v4l2_ctrl_ops isc_ctrl_ops = { |
1459 | .s_ctrl = isc_s_ctrl, |
1460 | }; |
1461 | |
1462 | static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) |
1463 | { |
1464 | struct isc_device *isc = container_of(ctrl->handler, |
1465 | struct isc_device, ctrls.handler); |
1466 | struct isc_ctrls *ctrls = &isc->ctrls; |
1467 | |
1468 | if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) |
1469 | return 0; |
1470 | |
1471 | switch (ctrl->id) { |
1472 | case V4L2_CID_AUTO_WHITE_BALANCE: |
1473 | if (ctrl->val == 1) |
1474 | ctrls->awb = ISC_WB_AUTO; |
1475 | else |
1476 | ctrls->awb = ISC_WB_NONE; |
1477 | |
1478 | /* configure the controls with new values from v4l2 */ |
1479 | if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new) |
1480 | ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val; |
1481 | if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new) |
1482 | ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val; |
1483 | if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new) |
1484 | ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val; |
1485 | if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new) |
1486 | ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val; |
1487 | |
1488 | if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new) |
1489 | ctrls->offset[ISC_HIS_CFG_MODE_R] = isc->r_off_ctrl->val; |
1490 | if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new) |
1491 | ctrls->offset[ISC_HIS_CFG_MODE_B] = isc->b_off_ctrl->val; |
1492 | if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new) |
1493 | ctrls->offset[ISC_HIS_CFG_MODE_GR] = isc->gr_off_ctrl->val; |
1494 | if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new) |
1495 | ctrls->offset[ISC_HIS_CFG_MODE_GB] = isc->gb_off_ctrl->val; |
1496 | |
1497 | isc_update_awb_ctrls(isc); |
1498 | |
1499 | mutex_lock(&isc->awb_mutex); |
1500 | if (vb2_is_streaming(q: &isc->vb2_vidq)) { |
1501 | /* |
1502 | * If we are streaming, we can update profile to |
1503 | * have the new settings in place. |
1504 | */ |
1505 | isc_update_profile(isc); |
1506 | } else { |
1507 | /* |
1508 | * The auto cluster will activate automatically this |
1509 | * control. This has to be deactivated when not |
1510 | * streaming. |
1511 | */ |
1512 | v4l2_ctrl_activate(ctrl: isc->do_wb_ctrl, active: false); |
1513 | } |
1514 | mutex_unlock(lock: &isc->awb_mutex); |
1515 | |
1516 | /* if we have autowhitebalance on, start histogram procedure */ |
1517 | if (ctrls->awb == ISC_WB_AUTO && |
1518 | vb2_is_streaming(q: &isc->vb2_vidq) && |
1519 | ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) |
1520 | isc_set_histogram(isc, enable: true); |
1521 | |
1522 | /* |
1523 | * for one time whitebalance adjustment, check the button, |
1524 | * if it's pressed, perform the one time operation. |
1525 | */ |
1526 | if (ctrls->awb == ISC_WB_NONE && |
1527 | ctrl->cluster[ISC_CTRL_DO_WB]->is_new && |
1528 | !(ctrl->cluster[ISC_CTRL_DO_WB]->flags & |
1529 | V4L2_CTRL_FLAG_INACTIVE)) { |
1530 | ctrls->awb = ISC_WB_ONETIME; |
1531 | isc_set_histogram(isc, enable: true); |
1532 | dev_dbg(isc->dev, "One time white-balance started.\n" ); |
1533 | } |
1534 | return 0; |
1535 | } |
1536 | return 0; |
1537 | } |
1538 | |
1539 | static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl) |
1540 | { |
1541 | struct isc_device *isc = container_of(ctrl->handler, |
1542 | struct isc_device, ctrls.handler); |
1543 | struct isc_ctrls *ctrls = &isc->ctrls; |
1544 | |
1545 | switch (ctrl->id) { |
1546 | /* being a cluster, this id will be called for every control */ |
1547 | case V4L2_CID_AUTO_WHITE_BALANCE: |
1548 | ctrl->cluster[ISC_CTRL_R_GAIN]->val = |
1549 | ctrls->gain[ISC_HIS_CFG_MODE_R]; |
1550 | ctrl->cluster[ISC_CTRL_B_GAIN]->val = |
1551 | ctrls->gain[ISC_HIS_CFG_MODE_B]; |
1552 | ctrl->cluster[ISC_CTRL_GR_GAIN]->val = |
1553 | ctrls->gain[ISC_HIS_CFG_MODE_GR]; |
1554 | ctrl->cluster[ISC_CTRL_GB_GAIN]->val = |
1555 | ctrls->gain[ISC_HIS_CFG_MODE_GB]; |
1556 | |
1557 | ctrl->cluster[ISC_CTRL_R_OFF]->val = |
1558 | ctrls->offset[ISC_HIS_CFG_MODE_R]; |
1559 | ctrl->cluster[ISC_CTRL_B_OFF]->val = |
1560 | ctrls->offset[ISC_HIS_CFG_MODE_B]; |
1561 | ctrl->cluster[ISC_CTRL_GR_OFF]->val = |
1562 | ctrls->offset[ISC_HIS_CFG_MODE_GR]; |
1563 | ctrl->cluster[ISC_CTRL_GB_OFF]->val = |
1564 | ctrls->offset[ISC_HIS_CFG_MODE_GB]; |
1565 | break; |
1566 | } |
1567 | return 0; |
1568 | } |
1569 | |
1570 | static const struct v4l2_ctrl_ops isc_awb_ops = { |
1571 | .s_ctrl = isc_s_awb_ctrl, |
1572 | .g_volatile_ctrl = isc_g_volatile_awb_ctrl, |
1573 | }; |
1574 | |
1575 | #define ISC_CTRL_OFF(_name, _id, _name_str) \ |
1576 | static const struct v4l2_ctrl_config _name = { \ |
1577 | .ops = &isc_awb_ops, \ |
1578 | .id = _id, \ |
1579 | .name = _name_str, \ |
1580 | .type = V4L2_CTRL_TYPE_INTEGER, \ |
1581 | .flags = V4L2_CTRL_FLAG_SLIDER, \ |
1582 | .min = -4095, \ |
1583 | .max = 4095, \ |
1584 | .step = 1, \ |
1585 | .def = 0, \ |
1586 | } |
1587 | |
1588 | ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset" ); |
1589 | ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset" ); |
1590 | ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset" ); |
1591 | ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset" ); |
1592 | |
1593 | #define ISC_CTRL_GAIN(_name, _id, _name_str) \ |
1594 | static const struct v4l2_ctrl_config _name = { \ |
1595 | .ops = &isc_awb_ops, \ |
1596 | .id = _id, \ |
1597 | .name = _name_str, \ |
1598 | .type = V4L2_CTRL_TYPE_INTEGER, \ |
1599 | .flags = V4L2_CTRL_FLAG_SLIDER, \ |
1600 | .min = 0, \ |
1601 | .max = 8191, \ |
1602 | .step = 1, \ |
1603 | .def = 512, \ |
1604 | } |
1605 | |
1606 | ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain" ); |
1607 | ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain" ); |
1608 | ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain" ); |
1609 | ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain" ); |
1610 | |
1611 | static int isc_ctrl_init(struct isc_device *isc) |
1612 | { |
1613 | const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; |
1614 | struct isc_ctrls *ctrls = &isc->ctrls; |
1615 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; |
1616 | int ret; |
1617 | |
1618 | ctrls->hist_stat = HIST_INIT; |
1619 | isc_reset_awb_ctrls(isc); |
1620 | |
1621 | ret = v4l2_ctrl_handler_init(hdl, 13); |
1622 | if (ret < 0) |
1623 | return ret; |
1624 | |
1625 | /* Initialize product specific controls. For example, contrast */ |
1626 | isc->config_ctrls(isc, ops); |
1627 | |
1628 | ctrls->brightness = 0; |
1629 | |
1630 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, min: -1024, max: 1023, step: 1, def: 0); |
1631 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, min: 0, max: isc->gamma_max, step: 1, |
1632 | def: isc->gamma_max); |
1633 | isc->awb_ctrl = v4l2_ctrl_new_std(hdl, ops: &isc_awb_ops, |
1634 | V4L2_CID_AUTO_WHITE_BALANCE, |
1635 | min: 0, max: 1, step: 1, def: 1); |
1636 | |
1637 | /* do_white_balance is a button, so min,max,step,default are ignored */ |
1638 | isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops: &isc_awb_ops, |
1639 | V4L2_CID_DO_WHITE_BALANCE, |
1640 | min: 0, max: 0, step: 0, def: 0); |
1641 | |
1642 | if (!isc->do_wb_ctrl) { |
1643 | ret = hdl->error; |
1644 | v4l2_ctrl_handler_free(hdl); |
1645 | return ret; |
1646 | } |
1647 | |
1648 | v4l2_ctrl_activate(ctrl: isc->do_wb_ctrl, active: false); |
1649 | |
1650 | isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_r_gain_ctrl, NULL); |
1651 | isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_b_gain_ctrl, NULL); |
1652 | isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_gr_gain_ctrl, NULL); |
1653 | isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_gb_gain_ctrl, NULL); |
1654 | isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_r_off_ctrl, NULL); |
1655 | isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_b_off_ctrl, NULL); |
1656 | isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_gr_off_ctrl, NULL); |
1657 | isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, cfg: &isc_gb_off_ctrl, NULL); |
1658 | |
1659 | /* |
1660 | * The cluster is in auto mode with autowhitebalance enabled |
1661 | * and manual mode otherwise. |
1662 | */ |
1663 | v4l2_ctrl_auto_cluster(ncontrols: 10, controls: &isc->awb_ctrl, manual_val: 0, set_volatile: true); |
1664 | |
1665 | v4l2_ctrl_handler_setup(hdl); |
1666 | |
1667 | return 0; |
1668 | } |
1669 | |
1670 | static int isc_async_bound(struct v4l2_async_notifier *notifier, |
1671 | struct v4l2_subdev *subdev, |
1672 | struct v4l2_async_connection *asd) |
1673 | { |
1674 | struct isc_device *isc = container_of(notifier->v4l2_dev, |
1675 | struct isc_device, v4l2_dev); |
1676 | struct isc_subdev_entity *subdev_entity = |
1677 | container_of(notifier, struct isc_subdev_entity, notifier); |
1678 | int pad; |
1679 | |
1680 | if (video_is_registered(vdev: &isc->video_dev)) { |
1681 | dev_err(isc->dev, "only supports one sub-device.\n" ); |
1682 | return -EBUSY; |
1683 | } |
1684 | |
1685 | subdev_entity->sd = subdev; |
1686 | |
1687 | pad = media_entity_get_fwnode_pad(entity: &subdev->entity, fwnode: asd->match.fwnode, |
1688 | MEDIA_PAD_FL_SOURCE); |
1689 | if (pad < 0) { |
1690 | dev_err(isc->dev, "failed to find pad for %s\n" , subdev->name); |
1691 | return pad; |
1692 | } |
1693 | |
1694 | isc->remote_pad = pad; |
1695 | |
1696 | return 0; |
1697 | } |
1698 | |
1699 | static void isc_async_unbind(struct v4l2_async_notifier *notifier, |
1700 | struct v4l2_subdev *subdev, |
1701 | struct v4l2_async_connection *asd) |
1702 | { |
1703 | struct isc_device *isc = container_of(notifier->v4l2_dev, |
1704 | struct isc_device, v4l2_dev); |
1705 | mutex_destroy(lock: &isc->awb_mutex); |
1706 | cancel_work_sync(work: &isc->awb_work); |
1707 | video_unregister_device(vdev: &isc->video_dev); |
1708 | v4l2_ctrl_handler_free(hdl: &isc->ctrls.handler); |
1709 | } |
1710 | |
1711 | struct isc_format *isc_find_format_by_code(struct isc_device *isc, |
1712 | unsigned int code, int *index) |
1713 | { |
1714 | struct isc_format *fmt = &isc->formats_list[0]; |
1715 | unsigned int i; |
1716 | |
1717 | for (i = 0; i < isc->formats_list_size; i++) { |
1718 | if (fmt->mbus_code == code) { |
1719 | *index = i; |
1720 | return fmt; |
1721 | } |
1722 | |
1723 | fmt++; |
1724 | } |
1725 | |
1726 | return NULL; |
1727 | } |
1728 | EXPORT_SYMBOL_GPL(isc_find_format_by_code); |
1729 | |
1730 | static int isc_set_default_fmt(struct isc_device *isc) |
1731 | { |
1732 | struct v4l2_format f = { |
1733 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, |
1734 | .fmt.pix = { |
1735 | .width = VGA_WIDTH, |
1736 | .height = VGA_HEIGHT, |
1737 | .field = V4L2_FIELD_NONE, |
1738 | .pixelformat = isc->controller_formats[0].fourcc, |
1739 | }, |
1740 | }; |
1741 | int ret; |
1742 | |
1743 | ret = isc_try_fmt(isc, f: &f); |
1744 | if (ret) |
1745 | return ret; |
1746 | |
1747 | isc->fmt = f; |
1748 | return 0; |
1749 | } |
1750 | |
1751 | static int isc_async_complete(struct v4l2_async_notifier *notifier) |
1752 | { |
1753 | struct isc_device *isc = container_of(notifier->v4l2_dev, |
1754 | struct isc_device, v4l2_dev); |
1755 | struct video_device *vdev = &isc->video_dev; |
1756 | struct vb2_queue *q = &isc->vb2_vidq; |
1757 | int ret = 0; |
1758 | |
1759 | INIT_WORK(&isc->awb_work, isc_awb_work); |
1760 | |
1761 | ret = v4l2_device_register_subdev_nodes(v4l2_dev: &isc->v4l2_dev); |
1762 | if (ret < 0) { |
1763 | dev_err(isc->dev, "Failed to register subdev nodes\n" ); |
1764 | return ret; |
1765 | } |
1766 | |
1767 | isc->current_subdev = container_of(notifier, |
1768 | struct isc_subdev_entity, notifier); |
1769 | mutex_init(&isc->lock); |
1770 | mutex_init(&isc->awb_mutex); |
1771 | |
1772 | init_completion(x: &isc->comp); |
1773 | |
1774 | /* Initialize videobuf2 queue */ |
1775 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1776 | q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; |
1777 | q->drv_priv = isc; |
1778 | q->buf_struct_size = sizeof(struct isc_buffer); |
1779 | q->ops = &isc_vb2_ops; |
1780 | q->mem_ops = &vb2_dma_contig_memops; |
1781 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1782 | q->lock = &isc->lock; |
1783 | q->min_queued_buffers = 1; |
1784 | q->dev = isc->dev; |
1785 | |
1786 | ret = vb2_queue_init(q); |
1787 | if (ret < 0) { |
1788 | dev_err(isc->dev, "vb2_queue_init() failed: %d\n" , ret); |
1789 | goto isc_async_complete_err; |
1790 | } |
1791 | |
1792 | /* Init video dma queues */ |
1793 | INIT_LIST_HEAD(list: &isc->dma_queue); |
1794 | spin_lock_init(&isc->dma_queue_lock); |
1795 | spin_lock_init(&isc->awb_lock); |
1796 | |
1797 | ret = isc_set_default_fmt(isc); |
1798 | if (ret) { |
1799 | dev_err(isc->dev, "Could not set default format\n" ); |
1800 | goto isc_async_complete_err; |
1801 | } |
1802 | |
1803 | ret = isc_ctrl_init(isc); |
1804 | if (ret) { |
1805 | dev_err(isc->dev, "Init isc ctrols failed: %d\n" , ret); |
1806 | goto isc_async_complete_err; |
1807 | } |
1808 | |
1809 | /* Register video device */ |
1810 | strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); |
1811 | vdev->release = video_device_release_empty; |
1812 | vdev->fops = &isc_fops; |
1813 | vdev->ioctl_ops = &isc_ioctl_ops; |
1814 | vdev->v4l2_dev = &isc->v4l2_dev; |
1815 | vdev->vfl_dir = VFL_DIR_RX; |
1816 | vdev->queue = q; |
1817 | vdev->lock = &isc->lock; |
1818 | vdev->ctrl_handler = &isc->ctrls.handler; |
1819 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | |
1820 | V4L2_CAP_IO_MC; |
1821 | video_set_drvdata(vdev, data: isc); |
1822 | |
1823 | ret = video_register_device(vdev, type: VFL_TYPE_VIDEO, nr: -1); |
1824 | if (ret < 0) { |
1825 | dev_err(isc->dev, "video_register_device failed: %d\n" , ret); |
1826 | goto isc_async_complete_err; |
1827 | } |
1828 | |
1829 | ret = isc_scaler_link(isc); |
1830 | if (ret < 0) |
1831 | goto isc_async_complete_unregister_device; |
1832 | |
1833 | ret = media_device_register(&isc->mdev); |
1834 | if (ret < 0) |
1835 | goto isc_async_complete_unregister_device; |
1836 | |
1837 | return 0; |
1838 | |
1839 | isc_async_complete_unregister_device: |
1840 | video_unregister_device(vdev); |
1841 | |
1842 | isc_async_complete_err: |
1843 | mutex_destroy(lock: &isc->awb_mutex); |
1844 | mutex_destroy(lock: &isc->lock); |
1845 | return ret; |
1846 | } |
1847 | |
1848 | const struct v4l2_async_notifier_operations microchip_isc_async_ops = { |
1849 | .bound = isc_async_bound, |
1850 | .unbind = isc_async_unbind, |
1851 | .complete = isc_async_complete, |
1852 | }; |
1853 | EXPORT_SYMBOL_GPL(microchip_isc_async_ops); |
1854 | |
1855 | void microchip_isc_subdev_cleanup(struct isc_device *isc) |
1856 | { |
1857 | struct isc_subdev_entity *subdev_entity; |
1858 | |
1859 | list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { |
1860 | v4l2_async_nf_unregister(notifier: &subdev_entity->notifier); |
1861 | v4l2_async_nf_cleanup(notifier: &subdev_entity->notifier); |
1862 | } |
1863 | |
1864 | INIT_LIST_HEAD(list: &isc->subdev_entities); |
1865 | } |
1866 | EXPORT_SYMBOL_GPL(microchip_isc_subdev_cleanup); |
1867 | |
1868 | int microchip_isc_pipeline_init(struct isc_device *isc) |
1869 | { |
1870 | struct device *dev = isc->dev; |
1871 | struct regmap *regmap = isc->regmap; |
1872 | struct regmap_field *regs; |
1873 | unsigned int i; |
1874 | |
1875 | /* |
1876 | * DPCEN-->GDCEN-->BLCEN-->WB-->CFA-->CC--> |
1877 | * GAM-->VHXS-->CSC-->CBC-->SUB422-->SUB420 |
1878 | */ |
1879 | const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = { |
1880 | REG_FIELD(ISC_DPC_CTRL, 0, 0), |
1881 | REG_FIELD(ISC_DPC_CTRL, 1, 1), |
1882 | REG_FIELD(ISC_DPC_CTRL, 2, 2), |
1883 | REG_FIELD(ISC_WB_CTRL, 0, 0), |
1884 | REG_FIELD(ISC_CFA_CTRL, 0, 0), |
1885 | REG_FIELD(ISC_CC_CTRL, 0, 0), |
1886 | REG_FIELD(ISC_GAM_CTRL, 0, 0), |
1887 | REG_FIELD(ISC_GAM_CTRL, 1, 1), |
1888 | REG_FIELD(ISC_GAM_CTRL, 2, 2), |
1889 | REG_FIELD(ISC_GAM_CTRL, 3, 3), |
1890 | REG_FIELD(ISC_VHXS_CTRL, 0, 0), |
1891 | REG_FIELD(ISC_CSC_CTRL + isc->offsets.csc, 0, 0), |
1892 | REG_FIELD(ISC_CBC_CTRL + isc->offsets.cbc, 0, 0), |
1893 | REG_FIELD(ISC_SUB422_CTRL + isc->offsets.sub422, 0, 0), |
1894 | REG_FIELD(ISC_SUB420_CTRL + isc->offsets.sub420, 0, 0), |
1895 | }; |
1896 | |
1897 | for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { |
1898 | regs = devm_regmap_field_alloc(dev, regmap, reg_field: regfields[i]); |
1899 | if (IS_ERR(ptr: regs)) |
1900 | return PTR_ERR(ptr: regs); |
1901 | |
1902 | isc->pipeline[i] = regs; |
1903 | } |
1904 | |
1905 | return 0; |
1906 | } |
1907 | EXPORT_SYMBOL_GPL(microchip_isc_pipeline_init); |
1908 | |
1909 | static int isc_link_validate(struct media_link *link) |
1910 | { |
1911 | struct video_device *vdev = |
1912 | media_entity_to_video_device(link->sink->entity); |
1913 | struct isc_device *isc = video_get_drvdata(vdev); |
1914 | int ret; |
1915 | |
1916 | ret = v4l2_subdev_link_validate(link); |
1917 | if (ret) |
1918 | return ret; |
1919 | |
1920 | return isc_validate(isc); |
1921 | } |
1922 | |
1923 | static const struct media_entity_operations isc_entity_operations = { |
1924 | .link_validate = isc_link_validate, |
1925 | }; |
1926 | |
1927 | int isc_mc_init(struct isc_device *isc, u32 ver) |
1928 | { |
1929 | const struct of_device_id *match; |
1930 | int ret; |
1931 | |
1932 | isc->video_dev.entity.function = MEDIA_ENT_F_IO_V4L; |
1933 | isc->video_dev.entity.flags = MEDIA_ENT_FL_DEFAULT; |
1934 | isc->video_dev.entity.ops = &isc_entity_operations; |
1935 | |
1936 | isc->pads[ISC_PAD_SINK].flags = MEDIA_PAD_FL_SINK; |
1937 | |
1938 | ret = media_entity_pads_init(entity: &isc->video_dev.entity, num_pads: ISC_PADS_NUM, |
1939 | pads: isc->pads); |
1940 | if (ret < 0) { |
1941 | dev_err(isc->dev, "media entity init failed\n" ); |
1942 | return ret; |
1943 | } |
1944 | |
1945 | isc->mdev.dev = isc->dev; |
1946 | |
1947 | match = of_match_node(matches: isc->dev->driver->of_match_table, |
1948 | node: isc->dev->of_node); |
1949 | |
1950 | strscpy(isc->mdev.driver_name, KBUILD_MODNAME, |
1951 | sizeof(isc->mdev.driver_name)); |
1952 | strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model)); |
1953 | isc->mdev.hw_revision = ver; |
1954 | |
1955 | media_device_init(mdev: &isc->mdev); |
1956 | |
1957 | isc->v4l2_dev.mdev = &isc->mdev; |
1958 | |
1959 | return isc_scaler_init(isc); |
1960 | } |
1961 | EXPORT_SYMBOL_GPL(isc_mc_init); |
1962 | |
1963 | void isc_mc_cleanup(struct isc_device *isc) |
1964 | { |
1965 | media_entity_cleanup(entity: &isc->video_dev.entity); |
1966 | media_device_cleanup(mdev: &isc->mdev); |
1967 | } |
1968 | EXPORT_SYMBOL_GPL(isc_mc_cleanup); |
1969 | |
1970 | /* regmap configuration */ |
1971 | #define MICROCHIP_ISC_REG_MAX 0xd5c |
1972 | const struct regmap_config microchip_isc_regmap_config = { |
1973 | .reg_bits = 32, |
1974 | .reg_stride = 4, |
1975 | .val_bits = 32, |
1976 | .max_register = MICROCHIP_ISC_REG_MAX, |
1977 | }; |
1978 | EXPORT_SYMBOL_GPL(microchip_isc_regmap_config); |
1979 | |
1980 | MODULE_AUTHOR("Songjun Wu" ); |
1981 | MODULE_AUTHOR("Eugen Hristev" ); |
1982 | MODULE_DESCRIPTION("Microchip ISC common code base" ); |
1983 | MODULE_LICENSE("GPL v2" ); |
1984 | |