1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2021-2022 Bootlin
4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
5 */
6
7#include <media/v4l2-device.h>
8#include <media/v4l2-event.h>
9#include <media/v4l2-ioctl.h>
10#include <media/v4l2-mc.h>
11#include <media/videobuf2-vmalloc.h>
12#include <media/videobuf2-v4l2.h>
13
14#include "sun6i_isp.h"
15#include "sun6i_isp_params.h"
16#include "sun6i_isp_reg.h"
17#include "uapi/sun6i-isp-config.h"
18
19/* Params */
20
21static const struct sun6i_isp_params_config sun6i_isp_params_config_default = {
22	.modules_used = SUN6I_ISP_MODULE_BAYER,
23
24	.bayer = {
25		.offset_r	= 32,
26		.offset_gr	= 32,
27		.offset_gb	= 32,
28		.offset_b	= 32,
29
30		.gain_r		= 256,
31		.gain_gr	= 256,
32		.gain_gb	= 256,
33		.gain_b		= 256,
34
35	},
36
37	.bdnf = {
38		.in_dis_min		= 8,
39		.in_dis_max		= 16,
40
41		.coefficients_g		= { 15, 4, 1 },
42		.coefficients_rb	= { 15, 4 },
43	},
44};
45
46static void sun6i_isp_params_configure_ob(struct sun6i_isp_device *isp_dev)
47{
48	unsigned int width, height;
49
50	sun6i_isp_proc_dimensions(isp_dev, &width, &height);
51
52	sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_SIZE_REG,
53			     SUN6I_ISP_OB_SIZE_WIDTH(width) |
54			     SUN6I_ISP_OB_SIZE_HEIGHT(height));
55
56	sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_VALID_REG,
57			     SUN6I_ISP_OB_VALID_WIDTH(width) |
58			     SUN6I_ISP_OB_VALID_HEIGHT(height));
59
60	sun6i_isp_load_write(isp_dev, SUN6I_ISP_OB_SRC0_VALID_START_REG,
61			     SUN6I_ISP_OB_SRC0_VALID_START_HORZ(0) |
62			     SUN6I_ISP_OB_SRC0_VALID_START_VERT(0));
63}
64
65static void sun6i_isp_params_configure_ae(struct sun6i_isp_device *isp_dev)
66{
67	/* These are default values that need to be set to get an output. */
68
69	sun6i_isp_load_write(isp_dev, SUN6I_ISP_AE_CFG_REG,
70			     SUN6I_ISP_AE_CFG_LOW_BRI_TH(0xff) |
71			     SUN6I_ISP_AE_CFG_HORZ_NUM(8) |
72			     SUN6I_ISP_AE_CFG_HIGH_BRI_TH(0xf00) |
73			     SUN6I_ISP_AE_CFG_VERT_NUM(8));
74}
75
76static void
77sun6i_isp_params_configure_bayer(struct sun6i_isp_device *isp_dev,
78				 const struct sun6i_isp_params_config *config)
79{
80	const struct sun6i_isp_params_config_bayer *bayer = &config->bayer;
81
82	sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_OFFSET0_REG,
83			     SUN6I_ISP_BAYER_OFFSET0_R(bayer->offset_r) |
84			     SUN6I_ISP_BAYER_OFFSET0_GR(bayer->offset_gr));
85
86	sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_OFFSET1_REG,
87			     SUN6I_ISP_BAYER_OFFSET1_GB(bayer->offset_gb) |
88			     SUN6I_ISP_BAYER_OFFSET1_B(bayer->offset_b));
89
90	sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_GAIN0_REG,
91			     SUN6I_ISP_BAYER_GAIN0_R(bayer->gain_r) |
92			     SUN6I_ISP_BAYER_GAIN0_GR(bayer->gain_gr));
93
94	sun6i_isp_load_write(isp_dev, SUN6I_ISP_BAYER_GAIN1_REG,
95			     SUN6I_ISP_BAYER_GAIN1_GB(bayer->gain_gb) |
96			     SUN6I_ISP_BAYER_GAIN1_B(bayer->gain_b));
97}
98
99static void sun6i_isp_params_configure_wb(struct sun6i_isp_device *isp_dev)
100{
101	/* These are default values that need to be set to get an output. */
102
103	sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_GAIN0_REG,
104			     SUN6I_ISP_WB_GAIN0_R(256) |
105			     SUN6I_ISP_WB_GAIN0_GR(256));
106
107	sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_GAIN1_REG,
108			     SUN6I_ISP_WB_GAIN1_GB(256) |
109			     SUN6I_ISP_WB_GAIN1_B(256));
110
111	sun6i_isp_load_write(isp_dev, SUN6I_ISP_WB_CFG_REG,
112			     SUN6I_ISP_WB_CFG_CLIP(0xfff));
113}
114
115static void sun6i_isp_params_configure_base(struct sun6i_isp_device *isp_dev)
116{
117	sun6i_isp_params_configure_ae(isp_dev);
118	sun6i_isp_params_configure_ob(isp_dev);
119	sun6i_isp_params_configure_wb(isp_dev);
120}
121
122static void
123sun6i_isp_params_configure_bdnf(struct sun6i_isp_device *isp_dev,
124				const struct sun6i_isp_params_config *config)
125{
126	const struct sun6i_isp_params_config_bdnf *bdnf = &config->bdnf;
127
128	sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_CFG_REG,
129			     SUN6I_ISP_BDNF_CFG_IN_DIS_MIN(bdnf->in_dis_min) |
130			     SUN6I_ISP_BDNF_CFG_IN_DIS_MAX(bdnf->in_dis_max));
131
132	sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_COEF_RB_REG,
133			     SUN6I_ISP_BDNF_COEF_RB(0, bdnf->coefficients_rb[0]) |
134			     SUN6I_ISP_BDNF_COEF_RB(1, bdnf->coefficients_rb[1]) |
135			     SUN6I_ISP_BDNF_COEF_RB(2, bdnf->coefficients_rb[2]) |
136			     SUN6I_ISP_BDNF_COEF_RB(3, bdnf->coefficients_rb[3]) |
137			     SUN6I_ISP_BDNF_COEF_RB(4, bdnf->coefficients_rb[4]));
138
139	sun6i_isp_load_write(isp_dev, SUN6I_ISP_BDNF_COEF_G_REG,
140			     SUN6I_ISP_BDNF_COEF_G(0, bdnf->coefficients_g[0]) |
141			     SUN6I_ISP_BDNF_COEF_G(1, bdnf->coefficients_g[1]) |
142			     SUN6I_ISP_BDNF_COEF_G(2, bdnf->coefficients_g[2]) |
143			     SUN6I_ISP_BDNF_COEF_G(3, bdnf->coefficients_g[3]) |
144			     SUN6I_ISP_BDNF_COEF_G(4, bdnf->coefficients_g[4]) |
145			     SUN6I_ISP_BDNF_COEF_G(5, bdnf->coefficients_g[5]) |
146			     SUN6I_ISP_BDNF_COEF_G(6, bdnf->coefficients_g[6]));
147}
148
149static void
150sun6i_isp_params_configure_modules(struct sun6i_isp_device *isp_dev,
151				   const struct sun6i_isp_params_config *config)
152{
153	u32 value;
154
155	if (config->modules_used & SUN6I_ISP_MODULE_BDNF)
156		sun6i_isp_params_configure_bdnf(isp_dev, config);
157
158	if (config->modules_used & SUN6I_ISP_MODULE_BAYER)
159		sun6i_isp_params_configure_bayer(isp_dev, config);
160
161	value = sun6i_isp_load_read(isp_dev, SUN6I_ISP_MODULE_EN_REG);
162	/* Clear all modules but keep input configuration. */
163	value &= SUN6I_ISP_MODULE_EN_SRC0 | SUN6I_ISP_MODULE_EN_SRC1;
164
165	if (config->modules_used & SUN6I_ISP_MODULE_BDNF)
166		value |= SUN6I_ISP_MODULE_EN_BDNF;
167
168	/* Bayer stage is always enabled. */
169
170	sun6i_isp_load_write(isp_dev, SUN6I_ISP_MODULE_EN_REG, value);
171}
172
173void sun6i_isp_params_configure(struct sun6i_isp_device *isp_dev)
174{
175	struct sun6i_isp_params_state *state = &isp_dev->params.state;
176	unsigned long flags;
177
178	spin_lock_irqsave(&state->lock, flags);
179
180	sun6i_isp_params_configure_base(isp_dev);
181
182	/* Default config is only applied at the very first stream start. */
183	if (state->configured)
184		goto complete;
185
186	sun6i_isp_params_configure_modules(isp_dev,
187					   &sun6i_isp_params_config_default);
188
189	state->configured = true;
190
191complete:
192	spin_unlock_irqrestore(&state->lock, flags);
193}
194
195/* State */
196
197static void sun6i_isp_params_state_cleanup(struct sun6i_isp_device *isp_dev,
198					   bool error)
199{
200	struct sun6i_isp_params_state *state = &isp_dev->params.state;
201	struct sun6i_isp_buffer *isp_buffer;
202	struct vb2_buffer *vb2_buffer;
203	unsigned long flags;
204
205	spin_lock_irqsave(&state->lock, flags);
206
207	if (state->pending) {
208		vb2_buffer = &state->pending->v4l2_buffer.vb2_buf;
209		vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
210				VB2_BUF_STATE_QUEUED);
211
212		state->pending = NULL;
213	}
214
215	list_for_each_entry(isp_buffer, &state->queue, list) {
216		vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
217		vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
218				VB2_BUF_STATE_QUEUED);
219	}
220
221	INIT_LIST_HEAD(&state->queue);
222
223	spin_unlock_irqrestore(&state->lock, flags);
224}
225
226void sun6i_isp_params_state_update(struct sun6i_isp_device *isp_dev,
227				   bool *update)
228{
229	struct sun6i_isp_params_state *state = &isp_dev->params.state;
230	struct sun6i_isp_buffer *isp_buffer;
231	struct vb2_buffer *vb2_buffer;
232	const struct sun6i_isp_params_config *config;
233	unsigned long flags;
234
235	spin_lock_irqsave(&state->lock, flags);
236
237	if (list_empty(&state->queue))
238		goto complete;
239
240	if (state->pending)
241		goto complete;
242
243	isp_buffer = list_first_entry(&state->queue, struct sun6i_isp_buffer,
244				      list);
245
246	vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
247	config = vb2_plane_vaddr(vb2_buffer, 0);
248
249	sun6i_isp_params_configure_modules(isp_dev, config);
250
251	list_del(&isp_buffer->list);
252
253	state->pending = isp_buffer;
254
255	if (update)
256		*update = true;
257
258complete:
259	spin_unlock_irqrestore(&state->lock, flags);
260}
261
262void sun6i_isp_params_state_complete(struct sun6i_isp_device *isp_dev)
263{
264	struct sun6i_isp_params_state *state = &isp_dev->params.state;
265	struct sun6i_isp_buffer *isp_buffer;
266	struct vb2_buffer *vb2_buffer;
267	unsigned long flags;
268
269	spin_lock_irqsave(&state->lock, flags);
270
271	if (!state->pending)
272		goto complete;
273
274	isp_buffer = state->pending;
275	vb2_buffer = &isp_buffer->v4l2_buffer.vb2_buf;
276
277	vb2_buffer->timestamp = ktime_get_ns();
278
279	/* Parameters will be applied starting from the next frame. */
280	isp_buffer->v4l2_buffer.sequence = isp_dev->capture.state.sequence + 1;
281
282	vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE);
283
284	state->pending = NULL;
285
286complete:
287	spin_unlock_irqrestore(&state->lock, flags);
288}
289
290/* Queue */
291
292static int sun6i_isp_params_queue_setup(struct vb2_queue *queue,
293					unsigned int *buffers_count,
294					unsigned int *planes_count,
295					unsigned int sizes[],
296					struct device *alloc_devs[])
297{
298	struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
299	unsigned int size = isp_dev->params.format.fmt.meta.buffersize;
300
301	if (*planes_count)
302		return sizes[0] < size ? -EINVAL : 0;
303
304	*planes_count = 1;
305	sizes[0] = size;
306
307	return 0;
308}
309
310static int sun6i_isp_params_buffer_prepare(struct vb2_buffer *vb2_buffer)
311{
312	struct sun6i_isp_device *isp_dev =
313		vb2_get_drv_priv(vb2_buffer->vb2_queue);
314	struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
315	unsigned int size = isp_dev->params.format.fmt.meta.buffersize;
316
317	if (vb2_plane_size(vb2_buffer, 0) < size) {
318		v4l2_err(v4l2_dev, "buffer too small (%lu < %u)\n",
319			 vb2_plane_size(vb2_buffer, 0), size);
320		return -EINVAL;
321	}
322
323	vb2_set_plane_payload(vb2_buffer, 0, size);
324
325	return 0;
326}
327
328static void sun6i_isp_params_buffer_queue(struct vb2_buffer *vb2_buffer)
329{
330	struct sun6i_isp_device *isp_dev =
331		vb2_get_drv_priv(vb2_buffer->vb2_queue);
332	struct sun6i_isp_params_state *state = &isp_dev->params.state;
333	struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(vb2_buffer);
334	struct sun6i_isp_buffer *isp_buffer =
335		container_of(v4l2_buffer, struct sun6i_isp_buffer, v4l2_buffer);
336	bool capture_streaming = isp_dev->capture.state.streaming;
337	unsigned long flags;
338
339	spin_lock_irqsave(&state->lock, flags);
340	list_add_tail(&isp_buffer->list, &state->queue);
341	spin_unlock_irqrestore(&state->lock, flags);
342
343	if (state->streaming && capture_streaming)
344		sun6i_isp_state_update(isp_dev, false);
345}
346
347static int sun6i_isp_params_start_streaming(struct vb2_queue *queue,
348					    unsigned int count)
349{
350	struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
351	struct sun6i_isp_params_state *state = &isp_dev->params.state;
352	bool capture_streaming = isp_dev->capture.state.streaming;
353
354	state->streaming = true;
355
356	/*
357	 * Update the state as soon as possible if capture is streaming,
358	 * otherwise it will be applied when capture starts streaming.
359	 */
360
361	if (capture_streaming)
362		sun6i_isp_state_update(isp_dev, false);
363
364	return 0;
365}
366
367static void sun6i_isp_params_stop_streaming(struct vb2_queue *queue)
368{
369	struct sun6i_isp_device *isp_dev = vb2_get_drv_priv(queue);
370	struct sun6i_isp_params_state *state = &isp_dev->params.state;
371
372	state->streaming = false;
373	sun6i_isp_params_state_cleanup(isp_dev, true);
374}
375
376static const struct vb2_ops sun6i_isp_params_queue_ops = {
377	.queue_setup		= sun6i_isp_params_queue_setup,
378	.buf_prepare		= sun6i_isp_params_buffer_prepare,
379	.buf_queue		= sun6i_isp_params_buffer_queue,
380	.start_streaming	= sun6i_isp_params_start_streaming,
381	.stop_streaming		= sun6i_isp_params_stop_streaming,
382	.wait_prepare		= vb2_ops_wait_prepare,
383	.wait_finish		= vb2_ops_wait_finish,
384};
385
386/* Video Device */
387
388static int sun6i_isp_params_querycap(struct file *file, void *private,
389				     struct v4l2_capability *capability)
390{
391	struct sun6i_isp_device *isp_dev = video_drvdata(file);
392	struct video_device *video_dev = &isp_dev->params.video_dev;
393
394	strscpy(capability->driver, SUN6I_ISP_NAME, sizeof(capability->driver));
395	strscpy(capability->card, video_dev->name, sizeof(capability->card));
396	snprintf(capability->bus_info, sizeof(capability->bus_info),
397		 "platform:%s", dev_name(isp_dev->dev));
398
399	return 0;
400}
401
402static int sun6i_isp_params_enum_fmt(struct file *file, void *private,
403				     struct v4l2_fmtdesc *fmtdesc)
404{
405	struct sun6i_isp_device *isp_dev = video_drvdata(file);
406	struct v4l2_meta_format *params_format =
407		&isp_dev->params.format.fmt.meta;
408
409	if (fmtdesc->index > 0)
410		return -EINVAL;
411
412	fmtdesc->pixelformat = params_format->dataformat;
413
414	return 0;
415}
416
417static int sun6i_isp_params_g_fmt(struct file *file, void *private,
418				  struct v4l2_format *format)
419{
420	struct sun6i_isp_device *isp_dev = video_drvdata(file);
421
422	*format = isp_dev->params.format;
423
424	return 0;
425}
426
427static const struct v4l2_ioctl_ops sun6i_isp_params_ioctl_ops = {
428	.vidioc_querycap		= sun6i_isp_params_querycap,
429
430	.vidioc_enum_fmt_meta_out	= sun6i_isp_params_enum_fmt,
431	.vidioc_g_fmt_meta_out		= sun6i_isp_params_g_fmt,
432	.vidioc_s_fmt_meta_out		= sun6i_isp_params_g_fmt,
433	.vidioc_try_fmt_meta_out	= sun6i_isp_params_g_fmt,
434
435	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
436	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
437	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
438	.vidioc_querybuf		= vb2_ioctl_querybuf,
439	.vidioc_expbuf			= vb2_ioctl_expbuf,
440	.vidioc_qbuf			= vb2_ioctl_qbuf,
441	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
442	.vidioc_streamon		= vb2_ioctl_streamon,
443	.vidioc_streamoff		= vb2_ioctl_streamoff,
444};
445
446static const struct v4l2_file_operations sun6i_isp_params_fops = {
447	.owner		= THIS_MODULE,
448	.unlocked_ioctl	= video_ioctl2,
449	.open		= v4l2_fh_open,
450	.release	= vb2_fop_release,
451	.mmap		= vb2_fop_mmap,
452	.poll		= vb2_fop_poll,
453};
454
455/* Params */
456
457int sun6i_isp_params_setup(struct sun6i_isp_device *isp_dev)
458{
459	struct sun6i_isp_params *params = &isp_dev->params;
460	struct sun6i_isp_params_state *state = &params->state;
461	struct v4l2_device *v4l2_dev = &isp_dev->v4l2.v4l2_dev;
462	struct v4l2_subdev *proc_subdev = &isp_dev->proc.subdev;
463	struct video_device *video_dev = &params->video_dev;
464	struct vb2_queue *queue = &isp_dev->params.queue;
465	struct media_pad *pad = &isp_dev->params.pad;
466	struct v4l2_format *format = &isp_dev->params.format;
467	struct v4l2_meta_format *params_format = &format->fmt.meta;
468	int ret;
469
470	/* State */
471
472	INIT_LIST_HEAD(&state->queue);
473	spin_lock_init(&state->lock);
474
475	/* Media Pads */
476
477	pad->flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
478
479	ret = media_entity_pads_init(&video_dev->entity, 1, pad);
480	if (ret)
481		goto error_mutex;
482
483	/* Queue */
484
485	mutex_init(&params->lock);
486
487	queue->type = V4L2_BUF_TYPE_META_OUTPUT;
488	queue->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
489	queue->buf_struct_size = sizeof(struct sun6i_isp_buffer);
490	queue->ops = &sun6i_isp_params_queue_ops;
491	queue->mem_ops = &vb2_vmalloc_memops;
492	queue->min_queued_buffers = 1;
493	queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
494	queue->lock = &params->lock;
495	queue->dev = isp_dev->dev;
496	queue->drv_priv = isp_dev;
497
498	ret = vb2_queue_init(queue);
499	if (ret) {
500		v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
501		goto error_media_entity;
502	}
503
504	/* V4L2 Format */
505
506	format->type = queue->type;
507	params_format->dataformat = V4L2_META_FMT_SUN6I_ISP_PARAMS;
508	params_format->buffersize = sizeof(struct sun6i_isp_params_config);
509
510	/* Video Device */
511
512	strscpy(video_dev->name, SUN6I_ISP_PARAMS_NAME,
513		sizeof(video_dev->name));
514	video_dev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING;
515	video_dev->vfl_dir = VFL_DIR_TX;
516	video_dev->release = video_device_release_empty;
517	video_dev->fops = &sun6i_isp_params_fops;
518	video_dev->ioctl_ops = &sun6i_isp_params_ioctl_ops;
519	video_dev->v4l2_dev = v4l2_dev;
520	video_dev->queue = queue;
521	video_dev->lock = &params->lock;
522
523	video_set_drvdata(video_dev, isp_dev);
524
525	ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
526	if (ret) {
527		v4l2_err(v4l2_dev, "failed to register video device: %d\n",
528			 ret);
529		goto error_media_entity;
530	}
531
532	/* Media Pad Link */
533
534	ret = media_create_pad_link(&video_dev->entity, 0,
535				    &proc_subdev->entity,
536				    SUN6I_ISP_PROC_PAD_SINK_PARAMS,
537				    MEDIA_LNK_FL_ENABLED |
538				    MEDIA_LNK_FL_IMMUTABLE);
539	if (ret < 0) {
540		v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n",
541			 video_dev->entity.name, 0, proc_subdev->entity.name,
542			 SUN6I_ISP_PROC_PAD_SINK_PARAMS);
543		goto error_video_device;
544	}
545
546	return 0;
547
548error_video_device:
549	vb2_video_unregister_device(video_dev);
550
551error_media_entity:
552	media_entity_cleanup(&video_dev->entity);
553
554error_mutex:
555	mutex_destroy(&params->lock);
556
557	return ret;
558}
559
560void sun6i_isp_params_cleanup(struct sun6i_isp_device *isp_dev)
561{
562	struct sun6i_isp_params *params = &isp_dev->params;
563	struct video_device *video_dev = &params->video_dev;
564
565	vb2_video_unregister_device(video_dev);
566	media_entity_cleanup(&video_dev->entity);
567	mutex_destroy(&params->lock);
568}
569