File Index
Files and directories
Sign in
FILE

sun6i_csi_capture.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c C
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
   4 * Author: Yong Deng <yong.deng@magewell.com>
   5 * Copyright 2021-2022 Bootlin
   6 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
   7 */
   8
   9#include <linux/of.h>
  10#include <linux/regmap.h>
  11#include <media/v4l2-device.h>
  12#include <media/v4l2-event.h>
  13#include <media/v4l2-ioctl.h>
  14#include <media/v4l2-mc.h>
  15#include <media/videobuf2-dma-contig.h>
  16#include <media/videobuf2-v4l2.h>
  17
  18#include "sun6i_csi.h"
  19#include "sun6i_csi_bridge.h"
  20#include "sun6i_csi_capture.h"
  21#include "sun6i_csi_reg.h"
  22
  23/* Helpers */
  24
  25void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev,
  26				  unsigned int *width, unsigned int *height)
  27{
  28	if (width)
  29		*width = csi_dev->capture.format.fmt.pix.width;
  30	if (height)
  31		*height = csi_dev->capture.format.fmt.pix.height;
  32}
  33
  34void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev,
  35			      u32 *pixelformat, u32 *field)
  36{
  37	if (pixelformat)
  38		*pixelformat = csi_dev->capture.format.fmt.pix.pixelformat;
  39
  40	if (field)
  41		*field = csi_dev->capture.format.fmt.pix.field;
  42}
  43
  44/* Format */
  45
  46static const struct sun6i_csi_capture_format sun6i_csi_capture_formats[] = {
  47	/* Bayer */
  48	{
  49		.pixelformat		= V4L2_PIX_FMT_SBGGR8,
  50		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
  51		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
  52	},
  53	{
  54		.pixelformat		= V4L2_PIX_FMT_SGBRG8,
  55		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
  56		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
  57	},
  58	{
  59		.pixelformat		= V4L2_PIX_FMT_SGRBG8,
  60		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
  61		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
  62	},
  63	{
  64		.pixelformat		= V4L2_PIX_FMT_SRGGB8,
  65		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
  66		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
  67	},
  68	{
  69		.pixelformat		= V4L2_PIX_FMT_SBGGR10,
  70		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
  71		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
  72	},
  73	{
  74		.pixelformat		= V4L2_PIX_FMT_SGBRG10,
  75		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
  76		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
  77	},
  78	{
  79		.pixelformat		= V4L2_PIX_FMT_SGRBG10,
  80		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
  81		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
  82	},
  83	{
  84		.pixelformat		= V4L2_PIX_FMT_SRGGB10,
  85		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10,
  86		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10,
  87	},
  88	{
  89		.pixelformat		= V4L2_PIX_FMT_SBGGR12,
  90		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
  91		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
  92	},
  93	{
  94		.pixelformat		= V4L2_PIX_FMT_SGBRG12,
  95		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
  96		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
  97	},
  98	{
  99		.pixelformat		= V4L2_PIX_FMT_SGRBG12,
 100		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
 101		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
 102	},
 103	{
 104		.pixelformat		= V4L2_PIX_FMT_SRGGB12,
 105		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12,
 106		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12,
 107	},
 108	/* RGB */
 109	{
 110		.pixelformat		= V4L2_PIX_FMT_RGB565,
 111		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565,
 112		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565,
 113	},
 114	{
 115		.pixelformat		= V4L2_PIX_FMT_RGB565X,
 116		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565,
 117		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565,
 118	},
 119	/* YUV422 */
 120	{
 121		.pixelformat		= V4L2_PIX_FMT_YUYV,
 122		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
 123		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
 124		.input_format_raw	= true,
 125		.hsize_len_factor	= 2,
 126	},
 127	{
 128		.pixelformat		= V4L2_PIX_FMT_YVYU,
 129		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
 130		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
 131		.input_format_raw	= true,
 132		.hsize_len_factor	= 2,
 133	},
 134	{
 135		.pixelformat		= V4L2_PIX_FMT_UYVY,
 136		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
 137		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
 138		.input_format_raw	= true,
 139		.hsize_len_factor	= 2,
 140	},
 141	{
 142		.pixelformat		= V4L2_PIX_FMT_VYUY,
 143		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
 144		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
 145		.input_format_raw	= true,
 146		.hsize_len_factor	= 2,
 147	},
 148	{
 149		.pixelformat		= V4L2_PIX_FMT_NV16,
 150		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP,
 151		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP,
 152	},
 153	{
 154		.pixelformat		= V4L2_PIX_FMT_NV61,
 155		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP,
 156		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP,
 157		.input_yuv_seq_invert	= true,
 158	},
 159	{
 160		.pixelformat		= V4L2_PIX_FMT_YUV422P,
 161		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422P,
 162		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422P,
 163	},
 164	/* YUV420 */
 165	{
 166		.pixelformat		= V4L2_PIX_FMT_NV12_16L16,
 167		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420MB,
 168		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420MB,
 169	},
 170	{
 171		.pixelformat		= V4L2_PIX_FMT_NV12,
 172		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP,
 173		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP,
 174	},
 175	{
 176		.pixelformat		= V4L2_PIX_FMT_NV21,
 177		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP,
 178		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP,
 179		.input_yuv_seq_invert	= true,
 180	},
 181
 182	{
 183		.pixelformat		= V4L2_PIX_FMT_YUV420,
 184		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P,
 185		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P,
 186	},
 187	{
 188		.pixelformat		= V4L2_PIX_FMT_YVU420,
 189		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P,
 190		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P,
 191		.input_yuv_seq_invert	= true,
 192	},
 193	/* Compressed */
 194	{
 195		.pixelformat		= V4L2_PIX_FMT_JPEG,
 196		.output_format_frame	= SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8,
 197		.output_format_field	= SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8,
 198	},
 199};
 200
 201const
 202struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat)
 203{
 204	unsigned int i;
 205
 206	for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++)
 207		if (sun6i_csi_capture_formats[i].pixelformat == pixelformat)
 208			return &sun6i_csi_capture_formats[i];
 209
 210	return NULL;
 211}
 212
 213/* RAW formats need an exact match between pixel and mbus formats. */
 214static const
 215struct sun6i_csi_capture_format_match sun6i_csi_capture_format_matches[] = {
 216	/* YUV420 */
 217	{
 218		.pixelformat	= V4L2_PIX_FMT_YUYV,
 219		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
 220	},
 221	{
 222		.pixelformat	= V4L2_PIX_FMT_YUYV,
 223		.mbus_code	= MEDIA_BUS_FMT_YUYV8_1X16,
 224	},
 225	{
 226		.pixelformat	= V4L2_PIX_FMT_YVYU,
 227		.mbus_code	= MEDIA_BUS_FMT_YVYU8_2X8,
 228	},
 229	{
 230		.pixelformat	= V4L2_PIX_FMT_YVYU,
 231		.mbus_code	= MEDIA_BUS_FMT_YVYU8_1X16,
 232	},
 233	{
 234		.pixelformat	= V4L2_PIX_FMT_UYVY,
 235		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8,
 236	},
 237	{
 238		.pixelformat	= V4L2_PIX_FMT_UYVY,
 239		.mbus_code	= MEDIA_BUS_FMT_UYVY8_1X16,
 240	},
 241	{
 242		.pixelformat	= V4L2_PIX_FMT_VYUY,
 243		.mbus_code	= MEDIA_BUS_FMT_VYUY8_2X8,
 244	},
 245	{
 246		.pixelformat	= V4L2_PIX_FMT_VYUY,
 247		.mbus_code	= MEDIA_BUS_FMT_VYUY8_1X16,
 248	},
 249	/* RGB */
 250	{
 251		.pixelformat	= V4L2_PIX_FMT_RGB565,
 252		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,
 253	},
 254	{
 255		.pixelformat	= V4L2_PIX_FMT_RGB565X,
 256		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_BE,
 257	},
 258	/* Bayer */
 259	{
 260		.pixelformat	= V4L2_PIX_FMT_SBGGR8,
 261		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
 262	},
 263	{
 264		.pixelformat	= V4L2_PIX_FMT_SGBRG8,
 265		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
 266	},
 267	{
 268		.pixelformat	= V4L2_PIX_FMT_SGRBG8,
 269		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
 270	},
 271	{
 272		.pixelformat	= V4L2_PIX_FMT_SRGGB8,
 273		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
 274	},
 275	{
 276		.pixelformat	= V4L2_PIX_FMT_SBGGR10,
 277		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
 278	},
 279	{
 280		.pixelformat	= V4L2_PIX_FMT_SGBRG10,
 281		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
 282	},
 283	{
 284		.pixelformat	= V4L2_PIX_FMT_SGRBG10,
 285		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
 286	},
 287	{
 288		.pixelformat	= V4L2_PIX_FMT_SRGGB10,
 289		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
 290	},
 291	{
 292		.pixelformat	= V4L2_PIX_FMT_SBGGR12,
 293		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
 294	},
 295	{
 296		.pixelformat	= V4L2_PIX_FMT_SGBRG12,
 297		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
 298	},
 299	{
 300		.pixelformat	= V4L2_PIX_FMT_SGRBG12,
 301		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
 302	},
 303	{
 304		.pixelformat	= V4L2_PIX_FMT_SRGGB12,
 305		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
 306	},
 307	/* Compressed */
 308	{
 309		.pixelformat	= V4L2_PIX_FMT_JPEG,
 310		.mbus_code	= MEDIA_BUS_FMT_JPEG_1X8,
 311	},
 312};
 313
 314static bool sun6i_csi_capture_format_match(u32 pixelformat, u32 mbus_code)
 315{
 316	unsigned int i;
 317
 318	for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_format_matches); i++) {
 319		const struct sun6i_csi_capture_format_match *match =
 320			&sun6i_csi_capture_format_matches[i];
 321
 322		if (match->pixelformat == pixelformat &&
 323		    match->mbus_code == mbus_code)
 324			return true;
 325	}
 326
 327	return false;
 328}
 329
 330/* Capture */
 331
 332static void
 333sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev,
 334				   struct sun6i_csi_buffer *csi_buffer)
 335{
 336	struct regmap *regmap = csi_dev->regmap;
 337	const struct v4l2_format_info *info;
 338	struct vb2_buffer *vb2_buffer;
 339	unsigned int width, height;
 340	dma_addr_t address;
 341	u32 pixelformat;
 342
 343	vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
 344	address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0);
 345
 346	regmap_write(regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG,
 347		     SUN6I_CSI_ADDR_VALUE(address));
 348
 349	sun6i_csi_capture_dimensions(csi_dev, &width, &height);
 350	sun6i_csi_capture_format(csi_dev, &pixelformat, NULL);
 351
 352	info = v4l2_format_info(pixelformat);
 353	/* Unsupported formats are single-plane, so we can stop here. */
 354	if (!info)
 355		return;
 356
 357	if (info->comp_planes > 1) {
 358		address += info->bpp[0] * width * height;
 359
 360		regmap_write(regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG,
 361			     SUN6I_CSI_ADDR_VALUE(address));
 362	}
 363
 364	if (info->comp_planes > 2) {
 365		address += info->bpp[1] * DIV_ROUND_UP(width, info->hdiv) *
 366			   DIV_ROUND_UP(height, info->vdiv);
 367
 368		regmap_write(regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG,
 369			     SUN6I_CSI_ADDR_VALUE(address));
 370	}
 371}
 372
 373void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev)
 374{
 375	struct regmap *regmap = csi_dev->regmap;
 376	const struct sun6i_csi_capture_format *format;
 377	const struct v4l2_format_info *info;
 378	u32 hsize_len, vsize_len;
 379	u32 luma_line, chroma_line = 0;
 380	u32 pixelformat, field;
 381	u32 width, height;
 382
 383	sun6i_csi_capture_dimensions(csi_dev, &width, &height);
 384	sun6i_csi_capture_format(csi_dev, &pixelformat, &field);
 385
 386	format = sun6i_csi_capture_format_find(pixelformat);
 387	if (WARN_ON(!format))
 388		return;
 389
 390	hsize_len = width;
 391	vsize_len = height;
 392
 393	/*
 394	 * When using 8-bit raw input/output (for packed YUV), we need to adapt
 395	 * the width to account for the difference in bpp when it's not 8-bit.
 396	 */
 397	if (format->hsize_len_factor)
 398		hsize_len *= format->hsize_len_factor;
 399
 400	regmap_write(regmap, SUN6I_CSI_CH_HSIZE_REG,
 401		     SUN6I_CSI_CH_HSIZE_LEN(hsize_len) |
 402		     SUN6I_CSI_CH_HSIZE_START(0));
 403
 404	regmap_write(regmap, SUN6I_CSI_CH_VSIZE_REG,
 405		     SUN6I_CSI_CH_VSIZE_LEN(vsize_len) |
 406		     SUN6I_CSI_CH_VSIZE_START(0));
 407
 408	switch (pixelformat) {
 409	case V4L2_PIX_FMT_RGB565X:
 410		luma_line = width * 2;
 411		break;
 412	case V4L2_PIX_FMT_NV12_16L16:
 413		luma_line = width;
 414		chroma_line = width;
 415		break;
 416	case V4L2_PIX_FMT_JPEG:
 417		luma_line = width;
 418		break;
 419	default:
 420		info = v4l2_format_info(pixelformat);
 421		if (WARN_ON(!info))
 422			return;
 423
 424		luma_line = width * info->bpp[0];
 425
 426		if (info->comp_planes > 1)
 427			chroma_line = width * info->bpp[1] / info->hdiv;
 428		break;
 429	}
 430
 431	regmap_write(regmap, SUN6I_CSI_CH_BUF_LEN_REG,
 432		     SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(chroma_line) |
 433		     SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(luma_line));
 434}
 435
 436/* State */
 437
 438static void sun6i_csi_capture_state_cleanup(struct sun6i_csi_device *csi_dev,
 439					    bool error)
 440{
 441	struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
 442	struct sun6i_csi_buffer **csi_buffer_states[] = {
 443		&state->pending, &state->current, &state->complete,
 444	};
 445	struct sun6i_csi_buffer *csi_buffer;
 446	struct vb2_buffer *vb2_buffer;
 447	unsigned long flags;
 448	unsigned int i;
 449
 450	spin_lock_irqsave(&state->lock, flags);
 451
 452	for (i = 0; i < ARRAY_SIZE(csi_buffer_states); i++) {
 453		csi_buffer = *csi_buffer_states[i];
 454		if (!csi_buffer)
 455			continue;
 456
 457		vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
 458		vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
 459				VB2_BUF_STATE_QUEUED);
 460
 461		*csi_buffer_states[i] = NULL;
 462	}
 463
 464	list_for_each_entry(csi_buffer, &state->queue, list) {
 465		vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf;
 466		vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR :
 467				VB2_BUF_STATE_QUEUED);
 468	}
 469
 470	INIT_LIST_HEAD(&state->queue);
 471
 472	spin_unlock_irqrestore(&state->lock, flags);
 473}
 474
 475void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev)
 476{
 477	struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
 478	struct sun6i_csi_buffer *csi_buffer;
 479	unsigned long flags;
 480
 481	spin_lock_irqsave(&state->lock, flags);
 482
 483	if (list_empty(&state->queue))
 484		goto complete;
 485
 486	if (state->pending)
 487		goto complete;
 488
 489	csi_buffer = list_first_entry(&state->queue, struct sun6i_csi_buffer,
 490				      list);
 491
 492	sun6i_csi_capture_buffer_configure(csi_dev, csi_buffer);
 493
 494	list_del(&csi_buffer->list);
 495
 496	state->pending = csi_buffer;
 497
 498complete:
 499	spin_unlock_irqrestore(&state->lock, flags);
 500}
 501
 502static void sun6i_csi_capture_state_complete(struct sun6i_csi_device *csi_dev)
 503{
 504	struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
 505	unsigned long flags;
 506
 507	spin_lock_irqsave(&state->lock, flags);
 508
 509	if (!state->pending)
 510		goto complete;
 511
 512	state->complete = state->current;
 513	state->current = state->pending;
 514	state->pending = NULL;
 515
 516	if (state->complete) {
 517		struct sun6i_csi_buffer *csi_buffer = state->complete;
 518		struct vb2_buffer *vb2_buffer =
 519			&csi_buffer->v4l2_buffer.vb2_buf;
 520
 521		vb2_buffer->timestamp = ktime_get_ns();
 522		csi_buffer->v4l2_buffer.sequence = state->sequence;
 523
 524		vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE);
 525
 526		state->complete = NULL;
 527	}
 528
 529complete:
 530	spin_unlock_irqrestore(&state->lock, flags);
 531}
 532
 533void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev)
 534{
 535	struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
 536	unsigned long flags;
 537
 538	spin_lock_irqsave(&state->lock, flags);
 539	state->sequence++;
 540	spin_unlock_irqrestore(&state->lock, flags);
 541}
 542
 543void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev)
 544{
 545	sun6i_csi_capture_state_complete(csi_dev);
 546	sun6i_csi_capture_state_update(csi_dev);
 547}
 548
 549/* Queue */
 550
 551static int sun6i_csi_capture_queue_setup(struct vb2_queue *queue,
 552					 unsigned int *buffers_count,
 553					 unsigned int *planes_count,
 554					 unsigned int sizes[],
 555					 struct device *alloc_devs[])
 556{
 557	struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
 558	unsigned int size = csi_dev->capture.format.fmt.pix.sizeimage;
 559
 560	if (*planes_count)
 561		return sizes[0] < size ? -EINVAL : 0;
 562
 563	*planes_count = 1;
 564	sizes[0] = size;
 565
 566	return 0;
 567}
 568
 569static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer)
 570{
 571	struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
 572	struct sun6i_csi_capture *capture = &csi_dev->capture;
 573	struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
 574	struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
 575	unsigned long size = capture->format.fmt.pix.sizeimage;
 576
 577	if (vb2_plane_size(buffer, 0) < size) {
 578		v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n",
 579			 vb2_plane_size(buffer, 0), size);
 580		return -EINVAL;
 581	}
 582
 583	vb2_set_plane_payload(buffer, 0, size);
 584
 585	v4l2_buffer->field = capture->format.fmt.pix.field;
 586
 587	return 0;
 588}
 589
 590static void sun6i_csi_capture_buffer_queue(struct vb2_buffer *buffer)
 591{
 592	struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue);
 593	struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
 594	struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer);
 595	struct sun6i_csi_buffer *csi_buffer =
 596		container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer);
 597	unsigned long flags;
 598
 599	spin_lock_irqsave(&state->lock, flags);
 600	list_add_tail(&csi_buffer->list, &state->queue);
 601	spin_unlock_irqrestore(&state->lock, flags);
 602}
 603
 604static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue,
 605					     unsigned int count)
 606{
 607	struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
 608	struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
 609	struct video_device *video_dev = &csi_dev->capture.video_dev;
 610	struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
 611	int ret;
 612
 613	state->sequence = 0;
 614
 615	ret = video_device_pipeline_alloc_start(video_dev);
 616	if (ret < 0)
 617		goto error_state;
 618
 619	state->streaming = true;
 620
 621	ret = v4l2_subdev_call(subdev, video, s_stream, 1);
 622	if (ret && ret != -ENOIOCTLCMD)
 623		goto error_streaming;
 624
 625	return 0;
 626
 627error_streaming:
 628	state->streaming = false;
 629
 630	video_device_pipeline_stop(video_dev);
 631
 632error_state:
 633	sun6i_csi_capture_state_cleanup(csi_dev, false);
 634
 635	return ret;
 636}
 637
 638static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue)
 639{
 640	struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue);
 641	struct sun6i_csi_capture_state *state = &csi_dev->capture.state;
 642	struct video_device *video_dev = &csi_dev->capture.video_dev;
 643	struct v4l2_subdev *subdev = &csi_dev->bridge.subdev;
 644
 645	v4l2_subdev_call(subdev, video, s_stream, 0);
 646
 647	state->streaming = false;
 648
 649	video_device_pipeline_stop(video_dev);
 650
 651	sun6i_csi_capture_state_cleanup(csi_dev, true);
 652}
 653
 654static const struct vb2_ops sun6i_csi_capture_queue_ops = {
 655	.queue_setup		= sun6i_csi_capture_queue_setup,
 656	.buf_prepare		= sun6i_csi_capture_buffer_prepare,
 657	.buf_queue		= sun6i_csi_capture_buffer_queue,
 658	.start_streaming	= sun6i_csi_capture_start_streaming,
 659	.stop_streaming		= sun6i_csi_capture_stop_streaming,
 660};
 661
 662/* V4L2 Device */
 663
 664static void sun6i_csi_capture_format_prepare(struct v4l2_format *format)
 665{
 666	struct v4l2_pix_format *pix_format = &format->fmt.pix;
 667	const struct v4l2_format_info *info;
 668	unsigned int width, height;
 669
 670	v4l_bound_align_image(&pix_format->width, SUN6I_CSI_CAPTURE_WIDTH_MIN,
 671			      SUN6I_CSI_CAPTURE_WIDTH_MAX, 1,
 672			      &pix_format->height, SUN6I_CSI_CAPTURE_HEIGHT_MIN,
 673			      SUN6I_CSI_CAPTURE_HEIGHT_MAX, 1, 0);
 674
 675	if (!sun6i_csi_capture_format_find(pix_format->pixelformat))
 676		pix_format->pixelformat =
 677			sun6i_csi_capture_formats[0].pixelformat;
 678
 679	width = pix_format->width;
 680	height = pix_format->height;
 681
 682	info = v4l2_format_info(pix_format->pixelformat);
 683
 684	switch (pix_format->pixelformat) {
 685	case V4L2_PIX_FMT_NV12_16L16:
 686		pix_format->bytesperline = width * 12 / 8;
 687		pix_format->sizeimage = pix_format->bytesperline * height;
 688		break;
 689	case V4L2_PIX_FMT_JPEG:
 690		pix_format->bytesperline = width;
 691		pix_format->sizeimage = pix_format->bytesperline * height;
 692		break;
 693	default:
 694		v4l2_fill_pixfmt(pix_format, pix_format->pixelformat,
 695				 width, height);
 696		break;
 697	}
 698
 699	if (pix_format->field == V4L2_FIELD_ANY)
 700		pix_format->field = V4L2_FIELD_NONE;
 701
 702	if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG)
 703		pix_format->colorspace = V4L2_COLORSPACE_JPEG;
 704	else if (info && info->pixel_enc == V4L2_PIXEL_ENC_BAYER)
 705		pix_format->colorspace = V4L2_COLORSPACE_RAW;
 706	else
 707		pix_format->colorspace = V4L2_COLORSPACE_SRGB;
 708
 709	pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
 710	pix_format->quantization = V4L2_QUANTIZATION_DEFAULT;
 711	pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
 712}
 713
 714static int sun6i_csi_capture_querycap(struct file *file, void *priv,
 715				      struct v4l2_capability *capability)
 716{
 717	struct sun6i_csi_device *csi_dev = video_drvdata(file);
 718	struct video_device *video_dev = &csi_dev->capture.video_dev;
 719
 720	strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver));
 721	strscpy(capability->card, video_dev->name, sizeof(capability->card));
 722	snprintf(capability->bus_info, sizeof(capability->bus_info),
 723		 "platform:%s", dev_name(csi_dev->dev));
 724
 725	return 0;
 726}
 727
 728static int sun6i_csi_capture_enum_fmt(struct file *file, void *priv,
 729				      struct v4l2_fmtdesc *fmtdesc)
 730{
 731	u32 index = fmtdesc->index;
 732
 733	if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
 734		return -EINVAL;
 735
 736	fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
 737
 738	return 0;
 739}
 740
 741static int sun6i_csi_capture_g_fmt(struct file *file, void *priv,
 742				   struct v4l2_format *format)
 743{
 744	struct sun6i_csi_device *csi_dev = video_drvdata(file);
 745
 746	*format = csi_dev->capture.format;
 747
 748	return 0;
 749}
 750
 751static int sun6i_csi_capture_s_fmt(struct file *file, void *priv,
 752				   struct v4l2_format *format)
 753{
 754	struct sun6i_csi_device *csi_dev = video_drvdata(file);
 755	struct sun6i_csi_capture *capture = &csi_dev->capture;
 756
 757	if (vb2_is_busy(&capture->queue))
 758		return -EBUSY;
 759
 760	sun6i_csi_capture_format_prepare(format);
 761
 762	csi_dev->capture.format = *format;
 763
 764	return 0;
 765}
 766
 767static int sun6i_csi_capture_try_fmt(struct file *file, void *priv,
 768				     struct v4l2_format *format)
 769{
 770	sun6i_csi_capture_format_prepare(format);
 771
 772	return 0;
 773}
 774
 775static int sun6i_csi_capture_enum_input(struct file *file, void *priv,
 776					struct v4l2_input *input)
 777{
 778	if (input->index != 0)
 779		return -EINVAL;
 780
 781	input->type = V4L2_INPUT_TYPE_CAMERA;
 782	strscpy(input->name, "Camera", sizeof(input->name));
 783
 784	return 0;
 785}
 786
 787static int sun6i_csi_capture_g_input(struct file *file, void *priv,
 788				     unsigned int *index)
 789{
 790	*index = 0;
 791
 792	return 0;
 793}
 794
 795static int sun6i_csi_capture_s_input(struct file *file, void *priv,
 796				     unsigned int index)
 797{
 798	if (index != 0)
 799		return -EINVAL;
 800
 801	return 0;
 802}
 803
 804static const struct v4l2_ioctl_ops sun6i_csi_capture_ioctl_ops = {
 805	.vidioc_querycap		= sun6i_csi_capture_querycap,
 806
 807	.vidioc_enum_fmt_vid_cap	= sun6i_csi_capture_enum_fmt,
 808	.vidioc_g_fmt_vid_cap		= sun6i_csi_capture_g_fmt,
 809	.vidioc_s_fmt_vid_cap		= sun6i_csi_capture_s_fmt,
 810	.vidioc_try_fmt_vid_cap		= sun6i_csi_capture_try_fmt,
 811
 812	.vidioc_enum_input		= sun6i_csi_capture_enum_input,
 813	.vidioc_g_input			= sun6i_csi_capture_g_input,
 814	.vidioc_s_input			= sun6i_csi_capture_s_input,
 815
 816	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
 817	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
 818	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
 819	.vidioc_querybuf		= vb2_ioctl_querybuf,
 820	.vidioc_expbuf			= vb2_ioctl_expbuf,
 821	.vidioc_qbuf			= vb2_ioctl_qbuf,
 822	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
 823	.vidioc_streamon		= vb2_ioctl_streamon,
 824	.vidioc_streamoff		= vb2_ioctl_streamoff,
 825};
 826
 827/* V4L2 File */
 828
 829static int sun6i_csi_capture_open(struct file *file)
 830{
 831	struct sun6i_csi_device *csi_dev = video_drvdata(file);
 832	struct sun6i_csi_capture *capture = &csi_dev->capture;
 833	int ret;
 834
 835	if (mutex_lock_interruptible(&capture->lock))
 836		return -ERESTARTSYS;
 837
 838	ret = v4l2_pipeline_pm_get(&capture->video_dev.entity);
 839	if (ret < 0)
 840		goto error_lock;
 841
 842	ret = v4l2_fh_open(file);
 843	if (ret < 0)
 844		goto error_pipeline;
 845
 846	mutex_unlock(&capture->lock);
 847
 848	return 0;
 849
 850error_pipeline:
 851	v4l2_pipeline_pm_put(&capture->video_dev.entity);
 852
 853error_lock:
 854	mutex_unlock(&capture->lock);
 855
 856	return ret;
 857}
 858
 859static int sun6i_csi_capture_close(struct file *file)
 860{
 861	struct sun6i_csi_device *csi_dev = video_drvdata(file);
 862	struct sun6i_csi_capture *capture = &csi_dev->capture;
 863
 864	mutex_lock(&capture->lock);
 865
 866	_vb2_fop_release(file, NULL);
 867	v4l2_pipeline_pm_put(&capture->video_dev.entity);
 868
 869	mutex_unlock(&capture->lock);
 870
 871	return 0;
 872}
 873
 874static const struct v4l2_file_operations sun6i_csi_capture_fops = {
 875	.owner		= THIS_MODULE,
 876	.open		= sun6i_csi_capture_open,
 877	.release	= sun6i_csi_capture_close,
 878	.unlocked_ioctl	= video_ioctl2,
 879	.mmap		= vb2_fop_mmap,
 880	.poll		= vb2_fop_poll
 881};
 882
 883/* Media Entity */
 884
 885static int sun6i_csi_capture_link_validate(struct media_link *link)
 886{
 887	struct video_device *video_dev =
 888		media_entity_to_video_device(link->sink->entity);
 889	struct sun6i_csi_device *csi_dev = video_get_drvdata(video_dev);
 890	struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
 891	const struct sun6i_csi_capture_format *capture_format;
 892	const struct sun6i_csi_bridge_format *bridge_format;
 893	unsigned int capture_width, capture_height;
 894	unsigned int bridge_width, bridge_height;
 895	const struct v4l2_format_info *format_info;
 896	u32 pixelformat, capture_field;
 897	u32 mbus_code, bridge_field;
 898	bool match;
 899
 900	sun6i_csi_capture_dimensions(csi_dev, &capture_width, &capture_height);
 901
 902	sun6i_csi_capture_format(csi_dev, &pixelformat, &capture_field);
 903	capture_format = sun6i_csi_capture_format_find(pixelformat);
 904	if (WARN_ON(!capture_format))
 905		return -EINVAL;
 906
 907	sun6i_csi_bridge_dimensions(csi_dev, &bridge_width, &bridge_height);
 908
 909	sun6i_csi_bridge_format(csi_dev, &mbus_code, &bridge_field);
 910	bridge_format = sun6i_csi_bridge_format_find(mbus_code);
 911	if (WARN_ON(!bridge_format))
 912		return -EINVAL;
 913
 914	/* No cropping/scaling is supported. */
 915	if (capture_width != bridge_width || capture_height != bridge_height) {
 916		v4l2_err(v4l2_dev,
 917			 "invalid input/output dimensions: %ux%u/%ux%u\n",
 918			 bridge_width, bridge_height, capture_width,
 919			 capture_height);
 920		return -EINVAL;
 921	}
 922
 923	format_info = v4l2_format_info(pixelformat);
 924	/* Some formats are not listed. */
 925	if (!format_info)
 926		return 0;
 927
 928	if (format_info->pixel_enc == V4L2_PIXEL_ENC_BAYER &&
 929	    bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
 930		goto invalid;
 931
 932	if (format_info->pixel_enc == V4L2_PIXEL_ENC_RGB &&
 933	    bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW)
 934		goto invalid;
 935
 936	if (format_info->pixel_enc == V4L2_PIXEL_ENC_YUV) {
 937		if (bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV420 &&
 938		    bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV422)
 939			goto invalid;
 940
 941		/* YUV420 input can't produce YUV422 output. */
 942		if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_YUV420 &&
 943		    format_info->vdiv == 1)
 944			goto invalid;
 945	}
 946
 947	/* With raw input mode, we need a 1:1 match between input and output. */
 948	if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_RAW ||
 949	    capture_format->input_format_raw) {
 950		match = sun6i_csi_capture_format_match(pixelformat, mbus_code);
 951		if (!match)
 952			goto invalid;
 953	}
 954
 955	return 0;
 956
 957invalid:
 958	v4l2_err(v4l2_dev, "invalid input/output format combination\n");
 959	return -EINVAL;
 960}
 961
 962static const struct media_entity_operations sun6i_csi_capture_media_ops = {
 963	.link_validate = sun6i_csi_capture_link_validate
 964};
 965
 966/* Capture */
 967
 968int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
 969{
 970	struct sun6i_csi_capture *capture = &csi_dev->capture;
 971	struct sun6i_csi_capture_state *state = &capture->state;
 972	struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
 973	struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev;
 974	struct video_device *video_dev = &capture->video_dev;
 975	struct vb2_queue *queue = &capture->queue;
 976	struct media_pad *pad = &capture->pad;
 977	struct v4l2_format *format = &csi_dev->capture.format;
 978	struct v4l2_pix_format *pix_format = &format->fmt.pix;
 979	int ret;
 980
 981	/* This may happen with multiple bridge notifier bound calls. */
 982	if (state->setup)
 983		return 0;
 984
 985	/* State */
 986
 987	INIT_LIST_HEAD(&state->queue);
 988	spin_lock_init(&state->lock);
 989
 990	/* Media Entity */
 991
 992	video_dev->entity.ops = &sun6i_csi_capture_media_ops;
 993
 994	/* Media Pad */
 995
 996	pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
 997
 998	ret = media_entity_pads_init(&video_dev->entity, 1, pad);
 999	if (ret < 0)
1000		return ret;
1001
1002	/* Queue */
1003
1004	mutex_init(&capture->lock);
1005
1006	queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1007	queue->io_modes = VB2_MMAP | VB2_DMABUF;
1008	queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
1009	queue->ops = &sun6i_csi_capture_queue_ops;
1010	queue->mem_ops = &vb2_dma_contig_memops;
1011	queue->min_queued_buffers = 2;
1012	queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1013	queue->lock = &capture->lock;
1014	queue->dev = csi_dev->dev;
1015	queue->drv_priv = csi_dev;
1016
1017	ret = vb2_queue_init(queue);
1018	if (ret) {
1019		v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret);
1020		goto error_media_entity;
1021	}
1022
1023	/* V4L2 Format */
1024
1025	format->type = queue->type;
1026	pix_format->pixelformat = sun6i_csi_capture_formats[0].pixelformat;
1027	pix_format->width = 1280;
1028	pix_format->height = 720;
1029	pix_format->field = V4L2_FIELD_NONE;
1030
1031	sun6i_csi_capture_format_prepare(format);
1032
1033	/* Video Device */
1034
1035	strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
1036		sizeof(video_dev->name));
1037	video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
1038	video_dev->vfl_dir = VFL_DIR_RX;
1039	video_dev->release = video_device_release_empty;
1040	video_dev->fops = &sun6i_csi_capture_fops;
1041	video_dev->ioctl_ops = &sun6i_csi_capture_ioctl_ops;
1042	video_dev->v4l2_dev = v4l2_dev;
1043	video_dev->queue = queue;
1044	video_dev->lock = &capture->lock;
1045
1046	video_set_drvdata(video_dev, csi_dev);
1047
1048	ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1);
1049	if (ret < 0) {
1050		v4l2_err(v4l2_dev, "failed to register video device: %d\n",
1051			 ret);
1052		goto error_media_entity;
1053	}
1054
1055	/* Media Pad Link */
1056
1057	ret = media_create_pad_link(&bridge_subdev->entity,
1058				    SUN6I_CSI_BRIDGE_PAD_SOURCE,
1059				    &video_dev->entity, 0,
1060				    csi_dev->isp_available ? 0 :
1061				    MEDIA_LNK_FL_ENABLED |
1062				    MEDIA_LNK_FL_IMMUTABLE);
1063	if (ret < 0) {
1064		v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n",
1065			 bridge_subdev->entity.name,
1066			 SUN6I_CSI_BRIDGE_PAD_SOURCE,
1067			 video_dev->entity.name, 0);
1068		goto error_video_device;
1069	}
1070
1071	state->setup = true;
1072
1073	return 0;
1074
1075error_video_device:
1076	vb2_video_unregister_device(video_dev);
1077
1078error_media_entity:
1079	media_entity_cleanup(&video_dev->entity);
1080
1081	mutex_destroy(&capture->lock);
1082
1083	return ret;
1084}
1085
1086void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev)
1087{
1088	struct sun6i_csi_capture *capture = &csi_dev->capture;
1089	struct video_device *video_dev = &capture->video_dev;
1090
1091	/* This may happen if async registration failed to complete. */
1092	if (!capture->state.setup)
1093		return;
1094
1095	vb2_video_unregister_device(video_dev);
1096	media_entity_cleanup(&video_dev->entity);
1097	mutex_destroy(&capture->lock);
1098
1099	capture->state.setup = false;
1100}
~/ Read-only file preview.