FILE
ipu6-isys-video.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2013--2024 Intel Corporation 4 */ 5 6#include <linux/align.h> 7#include <linux/bits.h> 8#include <linux/bug.h> 9#include <linux/completion.h> 10#include <linux/container_of.h> 11#include <linux/device.h> 12#include <linux/list.h> 13#include <linux/math64.h> 14#include <linux/minmax.h> 15#include <linux/module.h> 16#include <linux/mutex.h> 17#include <linux/pm_runtime.h> 18#include <linux/spinlock.h> 19#include <linux/string.h> 20 21#include <media/media-entity.h> 22#include <media/v4l2-ctrls.h> 23#include <media/v4l2-dev.h> 24#include <media/v4l2-fh.h> 25#include <media/v4l2-ioctl.h> 26#include <media/v4l2-subdev.h> 27#include <media/videobuf2-v4l2.h> 28 29#include "ipu6.h" 30#include "ipu6-bus.h" 31#include "ipu6-cpd.h" 32#include "ipu6-fw-isys.h" 33#include "ipu6-isys.h" 34#include "ipu6-isys-csi2.h" 35#include "ipu6-isys-queue.h" 36#include "ipu6-isys-video.h" 37#include "ipu6-platform-regs.h" 38 39const struct ipu6_isys_pixelformat ipu6_isys_pfmts[] = { 40 { V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12, 41 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 42 { V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12, 43 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 44 { V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12, 45 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 46 { V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12, 47 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 48 { V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10, 49 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 50 { V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10, 51 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 52 { V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10, 53 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 54 { V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10, 55 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 56 { V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8, 57 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 }, 58 { V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8, 59 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 }, 60 { V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8, 61 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 }, 62 { V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8, 63 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 }, 64 { V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12, 65 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 }, 66 { V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12, 67 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 }, 68 { V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12, 69 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 }, 70 { V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12, 71 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 }, 72 { V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10, 73 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, 74 { V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10, 75 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, 76 { V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10, 77 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, 78 { V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10, 79 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, 80 81 { V4L2_PIX_FMT_GREY, 8, 8, MEDIA_BUS_FMT_Y8_1X8, 82 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 }, 83 { V4L2_PIX_FMT_Y10, 16, 10, MEDIA_BUS_FMT_Y10_1X10, 84 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 85 { V4L2_PIX_FMT_Y12, 16, 12, MEDIA_BUS_FMT_Y12_1X12, 86 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 87 { V4L2_PIX_FMT_Y16, 16, 16, MEDIA_BUS_FMT_Y16_1X16, 88 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, 89 { V4L2_PIX_FMT_Y10P, 10, 10, MEDIA_BUS_FMT_Y10_1X10, 90 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, 91 { V4L2_PIX_FMT_Y12P, 12, 12, MEDIA_BUS_FMT_Y12_1X12, 92 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 }, 93 94 { V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, 95 IPU6_FW_ISYS_FRAME_FORMAT_UYVY}, 96 { V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16, 97 IPU6_FW_ISYS_FRAME_FORMAT_YUYV}, 98 { V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16, 99 IPU6_FW_ISYS_FRAME_FORMAT_RGB565 }, 100 { V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, 101 IPU6_FW_ISYS_FRAME_FORMAT_RGBA888 }, 102 { V4L2_META_FMT_GENERIC_8, 8, 8, MEDIA_BUS_FMT_META_8, 103 IPU6_FW_ISYS_FRAME_FORMAT_RAW8, true }, 104 { V4L2_META_FMT_GENERIC_CSI2_10, 10, 10, MEDIA_BUS_FMT_META_10, 105 IPU6_FW_ISYS_FRAME_FORMAT_RAW10, true }, 106 { V4L2_META_FMT_GENERIC_CSI2_12, 12, 12, MEDIA_BUS_FMT_META_12, 107 IPU6_FW_ISYS_FRAME_FORMAT_RAW12, true }, 108 { V4L2_META_FMT_GENERIC_CSI2_16, 16, 16, MEDIA_BUS_FMT_META_16, 109 IPU6_FW_ISYS_FRAME_FORMAT_RAW16, true }, 110}; 111 112static int video_open(struct file *file) 113{ 114 struct ipu6_isys_video *av = video_drvdata(file); 115 struct ipu6_isys *isys = av->isys; 116 struct ipu6_bus_device *adev = isys->adev; 117 118 mutex_lock(&isys->mutex); 119 if (isys->need_reset) { 120 mutex_unlock(&isys->mutex); 121 dev_warn(&adev->auxdev.dev, "isys power cycle required\n"); 122 return -EIO; 123 } 124 mutex_unlock(&isys->mutex); 125 126 return v4l2_fh_open(file); 127} 128 129const struct ipu6_isys_pixelformat * 130ipu6_isys_get_isys_format(u32 pixelformat, u32 type) 131{ 132 const struct ipu6_isys_pixelformat *default_pfmt = NULL; 133 unsigned int i; 134 135 for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) { 136 const struct ipu6_isys_pixelformat *pfmt = &ipu6_isys_pfmts[i]; 137 138 if (type && ((!pfmt->is_meta && 139 type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || 140 (pfmt->is_meta && 141 type != V4L2_BUF_TYPE_META_CAPTURE))) 142 continue; 143 144 if (!default_pfmt) 145 default_pfmt = pfmt; 146 147 if (pfmt->pixelformat != pixelformat) 148 continue; 149 150 return pfmt; 151 } 152 153 return default_pfmt; 154} 155 156static int ipu6_isys_vidioc_querycap(struct file *file, void *fh, 157 struct v4l2_capability *cap) 158{ 159 struct ipu6_isys_video *av = video_drvdata(file); 160 161 strscpy(cap->driver, IPU6_ISYS_NAME, sizeof(cap->driver)); 162 strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card)); 163 164 return 0; 165} 166 167static int ipu6_isys_vidioc_enum_fmt(struct file *file, void *fh, 168 struct v4l2_fmtdesc *f) 169{ 170 unsigned int i, num_found; 171 172 for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) { 173 if ((ipu6_isys_pfmts[i].is_meta && 174 f->type != V4L2_BUF_TYPE_META_CAPTURE) || 175 (!ipu6_isys_pfmts[i].is_meta && 176 f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) 177 continue; 178 179 if (f->mbus_code && f->mbus_code != ipu6_isys_pfmts[i].code) 180 continue; 181 182 if (num_found < f->index) { 183 num_found++; 184 continue; 185 } 186 187 f->flags = 0; 188 f->pixelformat = ipu6_isys_pfmts[i].pixelformat; 189 190 return 0; 191 } 192 193 return -EINVAL; 194} 195 196static int ipu6_isys_vidioc_enum_framesizes(struct file *file, void *fh, 197 struct v4l2_frmsizeenum *fsize) 198{ 199 unsigned int i; 200 201 if (fsize->index > 0) 202 return -EINVAL; 203 204 for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) { 205 if (fsize->pixel_format != ipu6_isys_pfmts[i].pixelformat) 206 continue; 207 208 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 209 fsize->stepwise.min_width = IPU6_ISYS_MIN_WIDTH; 210 fsize->stepwise.max_width = IPU6_ISYS_MAX_WIDTH; 211 fsize->stepwise.min_height = IPU6_ISYS_MIN_HEIGHT; 212 fsize->stepwise.max_height = IPU6_ISYS_MAX_HEIGHT; 213 fsize->stepwise.step_width = 2; 214 fsize->stepwise.step_height = 2; 215 216 return 0; 217 } 218 219 return -EINVAL; 220} 221 222static int ipu6_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh, 223 struct v4l2_format *f) 224{ 225 struct ipu6_isys_video *av = video_drvdata(file); 226 227 f->fmt.pix = av->pix_fmt; 228 229 return 0; 230} 231 232static int ipu6_isys_vidioc_g_fmt_meta_cap(struct file *file, void *fh, 233 struct v4l2_format *f) 234{ 235 struct ipu6_isys_video *av = video_drvdata(file); 236 237 f->fmt.meta = av->meta_fmt; 238 239 return 0; 240} 241 242static void ipu6_isys_try_fmt_cap(struct ipu6_isys_video *av, u32 type, 243 u32 *format, u32 *width, u32 *height, 244 u32 *bytesperline, u32 *sizeimage) 245{ 246 const struct ipu6_isys_pixelformat *pfmt = 247 ipu6_isys_get_isys_format(*format, type); 248 249 *format = pfmt->pixelformat; 250 *width = clamp(*width, IPU6_ISYS_MIN_WIDTH, IPU6_ISYS_MAX_WIDTH); 251 *height = clamp(*height, IPU6_ISYS_MIN_HEIGHT, IPU6_ISYS_MAX_HEIGHT); 252 253 if (pfmt->bpp != pfmt->bpp_packed) 254 *bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE); 255 else 256 *bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE); 257 258 *bytesperline = ALIGN(*bytesperline, 64); 259 260 /* 261 * (height + 1) * bytesperline due to a hardware issue: the DMA unit 262 * is a power of two, and a line should be transferred as few units 263 * as possible. The result is that up to line length more data than 264 * the image size may be transferred to memory after the image. 265 * Another limitation is the GDA allocation unit size. For low 266 * resolution it gives a bigger number. Use larger one to avoid 267 * memory corruption. 268 */ 269 *sizeimage = *bytesperline * *height + 270 max(*bytesperline, 271 av->isys->pdata->ipdata->isys_dma_overshoot); 272} 273 274static void __ipu6_isys_vidioc_try_fmt_vid_cap(struct ipu6_isys_video *av, 275 struct v4l2_format *f) 276{ 277 ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat, 278 &f->fmt.pix.width, &f->fmt.pix.height, 279 &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage); 280 281 f->fmt.pix.field = V4L2_FIELD_NONE; 282 f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; 283 f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 284 f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT; 285 f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT; 286} 287 288static int ipu6_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh, 289 struct v4l2_format *f) 290{ 291 struct ipu6_isys_video *av = video_drvdata(file); 292 293 if (vb2_is_busy(&av->aq.vbq)) 294 return -EBUSY; 295 296 __ipu6_isys_vidioc_try_fmt_vid_cap(av, f); 297 298 return 0; 299} 300 301static int __ipu6_isys_vidioc_try_fmt_meta_cap(struct ipu6_isys_video *av, 302 struct v4l2_format *f) 303{ 304 ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.meta.dataformat, 305 &f->fmt.meta.width, &f->fmt.meta.height, 306 &f->fmt.meta.bytesperline, 307 &f->fmt.meta.buffersize); 308 309 return 0; 310} 311 312static int ipu6_isys_vidioc_try_fmt_meta_cap(struct file *file, void *fh, 313 struct v4l2_format *f) 314{ 315 struct ipu6_isys_video *av = video_drvdata(file); 316 317 __ipu6_isys_vidioc_try_fmt_meta_cap(av, f); 318 319 return 0; 320} 321 322static int ipu6_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh, 323 struct v4l2_format *f) 324{ 325 struct ipu6_isys_video *av = video_drvdata(file); 326 327 ipu6_isys_vidioc_try_fmt_vid_cap(file, fh, f); 328 av->pix_fmt = f->fmt.pix; 329 330 return 0; 331} 332 333static int ipu6_isys_vidioc_s_fmt_meta_cap(struct file *file, void *fh, 334 struct v4l2_format *f) 335{ 336 struct ipu6_isys_video *av = video_drvdata(file); 337 338 if (vb2_is_busy(&av->aq.vbq)) 339 return -EBUSY; 340 341 ipu6_isys_vidioc_try_fmt_meta_cap(file, fh, f); 342 av->meta_fmt = f->fmt.meta; 343 344 return 0; 345} 346 347static int ipu6_isys_vidioc_reqbufs(struct file *file, void *priv, 348 struct v4l2_requestbuffers *p) 349{ 350 struct ipu6_isys_video *av = video_drvdata(file); 351 int ret; 352 353 av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type); 354 av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type); 355 356 ret = vb2_queue_change_type(&av->aq.vbq, p->type); 357 if (ret) 358 return ret; 359 360 return vb2_ioctl_reqbufs(file, priv, p); 361} 362 363static int ipu6_isys_vidioc_create_bufs(struct file *file, void *priv, 364 struct v4l2_create_buffers *p) 365{ 366 struct ipu6_isys_video *av = video_drvdata(file); 367 int ret; 368 369 av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type); 370 av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type); 371 372 ret = vb2_queue_change_type(&av->aq.vbq, p->format.type); 373 if (ret) 374 return ret; 375 376 return vb2_ioctl_create_bufs(file, priv, p); 377} 378 379static int link_validate(struct media_link *link) 380{ 381 struct ipu6_isys_video *av = 382 container_of(link->sink, struct ipu6_isys_video, pad); 383 struct device *dev = &av->isys->adev->auxdev.dev; 384 struct v4l2_subdev_state *s_state; 385 struct v4l2_subdev *s_sd; 386 struct v4l2_mbus_framefmt *s_fmt; 387 struct media_pad *s_pad; 388 u32 s_stream, code; 389 int ret = -EPIPE; 390 391 if (!link->source->entity) 392 return ret; 393 394 s_sd = media_entity_to_v4l2_subdev(link->source->entity); 395 s_state = v4l2_subdev_get_unlocked_active_state(s_sd); 396 if (!s_state) 397 return ret; 398 399 dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n", 400 link->source->entity->name, link->source->index, 401 link->sink->entity->name); 402 403 s_pad = media_pad_remote_pad_first(&av->pad); 404 s_stream = ipu6_isys_get_src_stream_by_src_pad(s_sd, s_pad->index); 405 406 v4l2_subdev_lock_state(s_state); 407 408 s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream); 409 if (!s_fmt) { 410 dev_err(dev, "failed to get source pad format\n"); 411 goto unlock; 412 } 413 414 code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code; 415 416 if (s_fmt->width != ipu6_isys_get_frame_width(av) || 417 s_fmt->height != ipu6_isys_get_frame_height(av) || 418 s_fmt->code != code) { 419 dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n", 420 s_fmt->width, s_fmt->height, s_fmt->code, 421 ipu6_isys_get_frame_width(av), 422 ipu6_isys_get_frame_height(av), code); 423 goto unlock; 424 } 425 426 v4l2_subdev_unlock_state(s_state); 427 428 return 0; 429unlock: 430 v4l2_subdev_unlock_state(s_state); 431 432 return ret; 433} 434 435static void get_stream_opened(struct ipu6_isys_video *av) 436{ 437 unsigned long flags; 438 439 spin_lock_irqsave(&av->isys->streams_lock, flags); 440 av->isys->stream_opened++; 441 spin_unlock_irqrestore(&av->isys->streams_lock, flags); 442} 443 444static void put_stream_opened(struct ipu6_isys_video *av) 445{ 446 unsigned long flags; 447 448 spin_lock_irqsave(&av->isys->streams_lock, flags); 449 av->isys->stream_opened--; 450 spin_unlock_irqrestore(&av->isys->streams_lock, flags); 451} 452 453static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av, 454 struct ipu6_fw_isys_stream_cfg_data_abi *cfg) 455{ 456 struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad); 457 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity); 458 struct ipu6_fw_isys_input_pin_info_abi *input_pin; 459 struct ipu6_fw_isys_output_pin_info_abi *output_pin; 460 struct ipu6_isys_stream *stream = av->stream; 461 struct ipu6_isys_queue *aq = &av->aq; 462 struct v4l2_mbus_framefmt fmt; 463 const struct ipu6_isys_pixelformat *pfmt = 464 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0); 465 struct v4l2_rect v4l2_crop; 466 struct ipu6_isys *isys = av->isys; 467 struct device *dev = &isys->adev->auxdev.dev; 468 int input_pins = cfg->nof_input_pins++; 469 int output_pins; 470 u32 src_stream; 471 int ret; 472 473 src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index); 474 ret = ipu6_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream, 475 &fmt); 476 if (ret < 0) { 477 dev_err(dev, "can't get stream format (%d)\n", ret); 478 return ret; 479 } 480 481 ret = ipu6_isys_get_stream_pad_crop(sd, src_pad->index, src_stream, 482 &v4l2_crop); 483 if (ret < 0) { 484 dev_err(dev, "can't get stream crop (%d)\n", ret); 485 return ret; 486 } 487 488 input_pin = &cfg->input_pins[input_pins]; 489 input_pin->input_res.width = fmt.width; 490 input_pin->input_res.height = fmt.height; 491 input_pin->dt = av->dt; 492 input_pin->bits_per_pix = pfmt->bpp_packed; 493 input_pin->mapped_dt = 0x40; /* invalid mipi data type */ 494 input_pin->mipi_decompression = 0; 495 input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR; 496 input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ? 497 IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER : 498 IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL; 499 input_pin->crop_first_and_last_lines = v4l2_crop.top & 1; 500 501 output_pins = cfg->nof_output_pins++; 502 aq->fw_output = output_pins; 503 stream->output_pins_queue[output_pins] = aq; 504 505 output_pin = &cfg->output_pins[output_pins]; 506 output_pin->input_pin_id = input_pins; 507 output_pin->output_res.width = ipu6_isys_get_frame_width(av); 508 output_pin->output_res.height = ipu6_isys_get_frame_height(av); 509 510 output_pin->stride = ipu6_isys_get_bytes_per_line(av); 511 if (pfmt->bpp != pfmt->bpp_packed) 512 output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC; 513 else 514 output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI; 515 output_pin->ft = pfmt->css_pixelformat; 516 output_pin->send_irq = 1; 517 memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets)); 518 output_pin->s2m_pixel_soc_pixel_remapping = 519 S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING; 520 output_pin->csi_be_soc_pixel_remapping = 521 CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING; 522 523 output_pin->snoopable = true; 524 output_pin->error_handling_enable = false; 525 output_pin->sensor_type = isys->sensor_type++; 526 if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end) 527 isys->sensor_type = isys->pdata->ipdata->sensor_type_start; 528 529 return 0; 530} 531 532static int start_stream_firmware(struct ipu6_isys_video *av, 533 struct ipu6_isys_buffer_list *bl) 534{ 535 struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg; 536 struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL; 537 struct ipu6_isys_stream *stream = av->stream; 538 struct device *dev = &av->isys->adev->auxdev.dev; 539 struct isys_fw_msgs *msg = NULL; 540 struct ipu6_isys_queue *aq; 541 int ret, retout, tout; 542 u16 send_type; 543 544 msg = ipu6_get_fw_msg_buf(stream); 545 if (!msg) 546 return -ENOMEM; 547 548 stream_cfg = &msg->fw_msg.stream; 549 stream_cfg->src = stream->stream_source; 550 stream_cfg->vc = stream->vc; 551 stream_cfg->isl_use = 0; 552 stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL; 553 554 list_for_each_entry(aq, &stream->queues, node) { 555 struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq); 556 557 ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg); 558 if (ret < 0) { 559 ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); 560 return ret; 561 } 562 } 563 564 ipu6_fw_isys_dump_stream_cfg(dev, stream_cfg); 565 566 stream->nr_output_pins = stream_cfg->nof_output_pins; 567 568 reinit_completion(&stream->stream_open_completion); 569 570 ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle, 571 stream_cfg, msg->dma_addr, 572 sizeof(*stream_cfg), 573 IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN); 574 if (ret < 0) { 575 dev_err(dev, "can't open stream (%d)\n", ret); 576 ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); 577 return ret; 578 } 579 580 get_stream_opened(av); 581 582 tout = wait_for_completion_timeout(&stream->stream_open_completion, 583 IPU6_FW_CALL_TIMEOUT_JIFFIES); 584 585 ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); 586 587 if (!tout) { 588 dev_err(dev, "stream open time out\n"); 589 ret = -ETIMEDOUT; 590 goto out_put_stream_opened; 591 } 592 if (stream->error) { 593 dev_err(dev, "stream open error: %d\n", stream->error); 594 ret = -EIO; 595 goto out_put_stream_opened; 596 } 597 dev_dbg(dev, "start stream: open complete\n"); 598 599 if (bl) { 600 msg = ipu6_get_fw_msg_buf(stream); 601 if (!msg) { 602 ret = -ENOMEM; 603 goto out_put_stream_opened; 604 } 605 buf = &msg->fw_msg.frame; 606 ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl); 607 ipu6_isys_buffer_list_queue(bl, 608 IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0); 609 } 610 611 reinit_completion(&stream->stream_start_completion); 612 613 if (bl) { 614 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE; 615 ipu6_fw_isys_dump_frame_buff_set(dev, buf, 616 stream_cfg->nof_output_pins); 617 ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle, 618 buf, msg->dma_addr, 619 sizeof(*buf), send_type); 620 } else { 621 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START; 622 ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle, 623 send_type); 624 } 625 626 if (ret < 0) { 627 dev_err(dev, "can't start streaming (%d)\n", ret); 628 goto out_stream_close; 629 } 630 631 tout = wait_for_completion_timeout(&stream->stream_start_completion, 632 IPU6_FW_CALL_TIMEOUT_JIFFIES); 633 if (!tout) { 634 dev_err(dev, "stream start time out\n"); 635 ret = -ETIMEDOUT; 636 goto out_stream_close; 637 } 638 if (stream->error) { 639 dev_err(dev, "stream start error: %d\n", stream->error); 640 ret = -EIO; 641 goto out_stream_close; 642 } 643 dev_dbg(dev, "start stream: complete\n"); 644 645 return 0; 646 647out_stream_close: 648 reinit_completion(&stream->stream_close_completion); 649 650 retout = ipu6_fw_isys_simple_cmd(av->isys, 651 stream->stream_handle, 652 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE); 653 if (retout < 0) { 654 dev_dbg(dev, "can't close stream (%d)\n", retout); 655 goto out_put_stream_opened; 656 } 657 658 tout = wait_for_completion_timeout(&stream->stream_close_completion, 659 IPU6_FW_CALL_TIMEOUT_JIFFIES); 660 if (!tout) 661 dev_err(dev, "stream close time out\n"); 662 else if (stream->error) 663 dev_err(dev, "stream close error: %d\n", stream->error); 664 else 665 dev_dbg(dev, "stream close complete\n"); 666 667out_put_stream_opened: 668 put_stream_opened(av); 669 670 return ret; 671} 672 673static void stop_streaming_firmware(struct ipu6_isys_video *av) 674{ 675 struct device *dev = &av->isys->adev->auxdev.dev; 676 struct ipu6_isys_stream *stream = av->stream; 677 int ret, tout; 678 679 reinit_completion(&stream->stream_stop_completion); 680 681 ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle, 682 IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH); 683 684 if (ret < 0) { 685 dev_err(dev, "can't stop stream (%d)\n", ret); 686 return; 687 } 688 689 tout = wait_for_completion_timeout(&stream->stream_stop_completion, 690 IPU6_FW_CALL_TIMEOUT_JIFFIES); 691 if (!tout) 692 dev_warn(dev, "stream stop time out\n"); 693 else if (stream->error) 694 dev_warn(dev, "stream stop error: %d\n", stream->error); 695 else 696 dev_dbg(dev, "stop stream: complete\n"); 697} 698 699static void close_streaming_firmware(struct ipu6_isys_video *av) 700{ 701 struct ipu6_isys_stream *stream = av->stream; 702 struct device *dev = &av->isys->adev->auxdev.dev; 703 int ret, tout; 704 705 reinit_completion(&stream->stream_close_completion); 706 707 ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle, 708 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE); 709 if (ret < 0) { 710 dev_err(dev, "can't close stream (%d)\n", ret); 711 return; 712 } 713 714 tout = wait_for_completion_timeout(&stream->stream_close_completion, 715 IPU6_FW_CALL_TIMEOUT_JIFFIES); 716 if (!tout) 717 dev_warn(dev, "stream close time out\n"); 718 else if (stream->error) 719 dev_warn(dev, "stream close error: %d\n", stream->error); 720 else 721 dev_dbg(dev, "close stream: complete\n"); 722 723 put_stream_opened(av); 724} 725 726int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av, 727 struct media_entity *source_entity, 728 int nr_queues) 729{ 730 struct ipu6_isys_stream *stream = av->stream; 731 struct ipu6_isys_csi2 *csi2; 732 733 if (WARN_ON(stream->nr_streaming)) 734 return -EINVAL; 735 736 stream->nr_queues = nr_queues; 737 atomic_set(&stream->sequence, 0); 738 739 stream->seq_index = 0; 740 memset(stream->seq, 0, sizeof(stream->seq)); 741 742 if (WARN_ON(!list_empty(&stream->queues))) 743 return -EINVAL; 744 745 stream->stream_source = stream->asd->source; 746 csi2 = ipu6_isys_subdev_to_csi2(stream->asd); 747 csi2->receiver_errors = 0; 748 stream->source_entity = source_entity; 749 750 dev_dbg(&av->isys->adev->auxdev.dev, 751 "prepare stream: external entity %s\n", 752 stream->source_entity->name); 753 754 return 0; 755} 756 757void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av, 758 bool state) 759{ 760 struct ipu6_isys *isys = av->isys; 761 struct ipu6_isys_csi2 *csi2 = NULL; 762 struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark; 763 struct device *dev = &isys->adev->auxdev.dev; 764 struct v4l2_mbus_framefmt format; 765 struct v4l2_subdev *esd; 766 struct v4l2_control hb = { .id = V4L2_CID_HBLANK, .value = 0 }; 767 unsigned int bpp, lanes; 768 s64 link_freq = 0; 769 u64 pixel_rate = 0; 770 int ret; 771 772 if (!state) 773 return; 774 775 esd = media_entity_to_v4l2_subdev(av->stream->source_entity); 776 777 av->watermark.width = ipu6_isys_get_frame_width(av); 778 av->watermark.height = ipu6_isys_get_frame_height(av); 779 av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift; 780 av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size; 781 782 ret = v4l2_g_ctrl(esd->ctrl_handler, &hb); 783 if (!ret && hb.value >= 0) 784 av->watermark.hblank = hb.value; 785 else 786 av->watermark.hblank = 0; 787 788 csi2 = ipu6_isys_subdev_to_csi2(av->stream->asd); 789 link_freq = ipu6_isys_csi2_get_link_freq(csi2); 790 if (link_freq > 0) { 791 lanes = csi2->nlanes; 792 ret = ipu6_isys_get_stream_pad_fmt(&csi2->asd.sd, 0, 793 av->source_stream, &format); 794 if (!ret) { 795 bpp = ipu6_isys_mbus_code_to_bpp(format.code); 796 pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp); 797 } 798 } 799 800 av->watermark.pixel_rate = pixel_rate; 801 802 if (!pixel_rate) { 803 mutex_lock(&iwake_watermark->mutex); 804 iwake_watermark->force_iwake_disable = true; 805 mutex_unlock(&iwake_watermark->mutex); 806 dev_warn(dev, "unexpected pixel_rate from %s, disable iwake.\n", 807 av->stream->source_entity->name); 808 } 809} 810 811static void calculate_stream_datarate(struct ipu6_isys_video *av) 812{ 813 struct video_stream_watermark *watermark = &av->watermark; 814 const struct ipu6_isys_pixelformat *pfmt = 815 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0); 816 u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line; 817 u64 line_time_ns, stream_data_rate; 818 u16 shift, size; 819 820 shift = watermark->sram_gran_shift; 821 size = watermark->sram_gran_size; 822 823 pixels_per_line = watermark->width + watermark->hblank; 824 line_time_ns = div_u64(pixels_per_line * NSEC_PER_SEC, 825 watermark->pixel_rate); 826 bytes_per_line = watermark->width * pfmt->bpp / 8; 827 pages_per_line = DIV_ROUND_UP(bytes_per_line, size); 828 pb_bytes_per_line = pages_per_line << shift; 829 stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns); 830 831 watermark->stream_data_rate = stream_data_rate; 832} 833 834void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state) 835{ 836 struct isys_iwake_watermark *iwake_watermark = 837 &av->isys->iwake_watermark; 838 839 if (!av->watermark.pixel_rate) 840 return; 841 842 if (state) { 843 calculate_stream_datarate(av); 844 mutex_lock(&iwake_watermark->mutex); 845 list_add(&av->watermark.stream_node, 846 &iwake_watermark->video_list); 847 mutex_unlock(&iwake_watermark->mutex); 848 } else { 849 av->watermark.stream_data_rate = 0; 850 mutex_lock(&iwake_watermark->mutex); 851 list_del(&av->watermark.stream_node); 852 mutex_unlock(&iwake_watermark->mutex); 853 } 854 855 update_watermark_setting(av->isys); 856} 857 858void ipu6_isys_put_stream(struct ipu6_isys_stream *stream) 859{ 860 struct device *dev; 861 unsigned int i; 862 unsigned long flags; 863 864 if (!stream) { 865 pr_err("ipu6-isys: no available stream\n"); 866 return; 867 } 868 869 dev = &stream->isys->adev->auxdev.dev; 870 871 spin_lock_irqsave(&stream->isys->streams_lock, flags); 872 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) { 873 if (&stream->isys->streams[i] == stream) { 874 if (stream->isys->streams_ref_count[i] > 0) 875 stream->isys->streams_ref_count[i]--; 876 else 877 dev_warn(dev, "invalid stream %d\n", i); 878 879 break; 880 } 881 } 882 spin_unlock_irqrestore(&stream->isys->streams_lock, flags); 883} 884 885static struct ipu6_isys_stream * 886ipu6_isys_get_stream(struct ipu6_isys_video *av, struct ipu6_isys_subdev *asd) 887{ 888 struct ipu6_isys_stream *stream = NULL; 889 struct ipu6_isys *isys = av->isys; 890 unsigned long flags; 891 unsigned int i; 892 u8 vc = av->vc; 893 894 if (!isys) 895 return NULL; 896 897 spin_lock_irqsave(&isys->streams_lock, flags); 898 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) { 899 if (isys->streams_ref_count[i] && isys->streams[i].vc == vc && 900 isys->streams[i].asd == asd) { 901 isys->streams_ref_count[i]++; 902 stream = &isys->streams[i]; 903 break; 904 } 905 } 906 907 if (!stream) { 908 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) { 909 if (!isys->streams_ref_count[i]) { 910 isys->streams_ref_count[i]++; 911 stream = &isys->streams[i]; 912 stream->vc = vc; 913 stream->asd = asd; 914 break; 915 } 916 } 917 } 918 spin_unlock_irqrestore(&isys->streams_lock, flags); 919 920 return stream; 921} 922 923struct ipu6_isys_stream * 924ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle) 925{ 926 unsigned long flags; 927 struct ipu6_isys_stream *stream = NULL; 928 929 if (!isys) 930 return NULL; 931 932 if (stream_handle >= IPU6_ISYS_MAX_STREAMS) { 933 dev_err(&isys->adev->auxdev.dev, 934 "stream_handle %d is invalid\n", stream_handle); 935 return NULL; 936 } 937 938 spin_lock_irqsave(&isys->streams_lock, flags); 939 if (isys->streams_ref_count[stream_handle] > 0) { 940 isys->streams_ref_count[stream_handle]++; 941 stream = &isys->streams[stream_handle]; 942 } 943 spin_unlock_irqrestore(&isys->streams_lock, flags); 944 945 return stream; 946} 947 948struct ipu6_isys_stream * 949ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc) 950{ 951 struct ipu6_isys_stream *stream = NULL; 952 unsigned long flags; 953 unsigned int i; 954 955 if (!isys) 956 return NULL; 957 958 if (source < 0) { 959 dev_err(&isys->adev->auxdev.dev, 960 "query stream with invalid port number\n"); 961 return NULL; 962 } 963 964 spin_lock_irqsave(&isys->streams_lock, flags); 965 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) { 966 if (!isys->streams_ref_count[i]) 967 continue; 968 969 if (isys->streams[i].stream_source == source && 970 isys->streams[i].vc == vc) { 971 stream = &isys->streams[i]; 972 isys->streams_ref_count[i]++; 973 break; 974 } 975 } 976 spin_unlock_irqrestore(&isys->streams_lock, flags); 977 978 return stream; 979} 980 981static u64 get_stream_mask_by_pipeline(struct ipu6_isys_video *__av) 982{ 983 struct media_pipeline *pipeline = 984 media_entity_pipeline(&__av->vdev.entity); 985 unsigned int i; 986 u64 stream_mask = 0; 987 988 for (i = 0; i < NR_OF_CSI2_SRC_PADS; i++) { 989 struct ipu6_isys_video *av = &__av->csi2->av[i]; 990 991 if (pipeline == media_entity_pipeline(&av->vdev.entity)) 992 stream_mask |= BIT_ULL(av->source_stream); 993 } 994 995 return stream_mask; 996} 997 998int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state, 999 struct ipu6_isys_buffer_list *bl) 1000{ 1001 struct v4l2_subdev_krouting *routing; 1002 struct ipu6_isys_stream *stream = av->stream; 1003 struct v4l2_subdev_state *subdev_state; 1004 struct device *dev = &av->isys->adev->auxdev.dev; 1005 struct v4l2_subdev *sd; 1006 struct media_pad *r_pad; 1007 u32 sink_pad, sink_stream; 1008 u64 r_stream; 1009 u64 stream_mask = 0; 1010 int ret = 0; 1011 1012 dev_dbg(dev, "set stream: %d\n", state); 1013 1014 if (WARN(!stream->source_entity, "No source entity for stream\n")) 1015 return -ENODEV; 1016 1017 sd = &stream->asd->sd; 1018 r_pad = media_pad_remote_pad_first(&av->pad); 1019 r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index); 1020 1021 subdev_state = v4l2_subdev_lock_and_get_active_state(sd); 1022 routing = &subdev_state->routing; 1023 ret = v4l2_subdev_routing_find_opposite_end(routing, r_pad->index, 1024 r_stream, &sink_pad, 1025 &sink_stream); 1026 v4l2_subdev_unlock_state(subdev_state); 1027 if (ret) 1028 return ret; 1029 1030 stream_mask = get_stream_mask_by_pipeline(av); 1031 if (!state) { 1032 stop_streaming_firmware(av); 1033 1034 /* stop sub-device which connects with video */ 1035 dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n", 1036 sd->name, r_pad->index, stream_mask); 1037 ret = v4l2_subdev_disable_streams(sd, r_pad->index, 1038 stream_mask); 1039 if (ret) 1040 dev_err(dev, "stream off %s failed with %d\n", sd->name, 1041 ret); 1042 1043 close_streaming_firmware(av); 1044 } else { 1045 ret = start_stream_firmware(av, bl); 1046 if (ret) { 1047 dev_err(dev, "start stream of firmware failed\n"); 1048 return ret; 1049 } 1050 1051 /* start sub-device which connects with video */ 1052 dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name, 1053 r_pad->index, stream_mask); 1054 ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask); 1055 if (ret) { 1056 dev_err(dev, "stream on %s failed with %d\n", sd->name, 1057 ret); 1058 goto out_media_entity_stop_streaming_firmware; 1059 } 1060 } 1061 1062 av->streaming = state; 1063 1064 return 0; 1065 1066out_media_entity_stop_streaming_firmware: 1067 stop_streaming_firmware(av); 1068 close_streaming_firmware(av); 1069 1070 return ret; 1071} 1072 1073static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = { 1074 .vidioc_querycap = ipu6_isys_vidioc_querycap, 1075 .vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt, 1076 .vidioc_enum_fmt_meta_cap = ipu6_isys_vidioc_enum_fmt, 1077 .vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes, 1078 .vidioc_g_fmt_vid_cap = ipu6_isys_vidioc_g_fmt_vid_cap, 1079 .vidioc_s_fmt_vid_cap = ipu6_isys_vidioc_s_fmt_vid_cap, 1080 .vidioc_try_fmt_vid_cap = ipu6_isys_vidioc_try_fmt_vid_cap, 1081 .vidioc_g_fmt_meta_cap = ipu6_isys_vidioc_g_fmt_meta_cap, 1082 .vidioc_s_fmt_meta_cap = ipu6_isys_vidioc_s_fmt_meta_cap, 1083 .vidioc_try_fmt_meta_cap = ipu6_isys_vidioc_try_fmt_meta_cap, 1084 .vidioc_reqbufs = ipu6_isys_vidioc_reqbufs, 1085 .vidioc_create_bufs = ipu6_isys_vidioc_create_bufs, 1086 .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 1087 .vidioc_querybuf = vb2_ioctl_querybuf, 1088 .vidioc_qbuf = vb2_ioctl_qbuf, 1089 .vidioc_dqbuf = vb2_ioctl_dqbuf, 1090 .vidioc_streamon = vb2_ioctl_streamon, 1091 .vidioc_streamoff = vb2_ioctl_streamoff, 1092 .vidioc_expbuf = vb2_ioctl_expbuf, 1093}; 1094 1095static const struct media_entity_operations entity_ops = { 1096 .link_validate = link_validate, 1097}; 1098 1099static const struct v4l2_file_operations isys_fops = { 1100 .owner = THIS_MODULE, 1101 .poll = vb2_fop_poll, 1102 .unlocked_ioctl = video_ioctl2, 1103 .mmap = vb2_fop_mmap, 1104 .open = video_open, 1105 .release = vb2_fop_release, 1106}; 1107 1108int ipu6_isys_fw_open(struct ipu6_isys *isys) 1109{ 1110 struct ipu6_bus_device *adev = isys->adev; 1111 const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata; 1112 int ret; 1113 1114 ret = pm_runtime_resume_and_get(&adev->auxdev.dev); 1115 if (ret < 0) 1116 return ret; 1117 1118 mutex_lock(&isys->mutex); 1119 1120 if (isys->ref_count++) 1121 goto unlock; 1122 1123 ipu6_configure_spc(adev->isp, &ipdata->hw_variant, 1124 IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX, isys->pdata->base, 1125 adev->pkg_dir, adev->pkg_dir_dma_addr); 1126 1127 /* 1128 * Buffers could have been left to wrong queue at last closure. 1129 * Move them now back to empty buffer queue. 1130 */ 1131 ipu6_cleanup_fw_msg_bufs(isys); 1132 1133 if (isys->fwcom) { 1134 /* 1135 * Something went wrong in previous shutdown. As we are now 1136 * restarting isys we can safely delete old context. 1137 */ 1138 dev_warn(&adev->auxdev.dev, "clearing old context\n"); 1139 ipu6_fw_isys_cleanup(isys); 1140 } 1141 1142 ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams); 1143 if (ret < 0) 1144 goto out; 1145 1146unlock: 1147 mutex_unlock(&isys->mutex); 1148 1149 return 0; 1150 1151out: 1152 isys->ref_count--; 1153 mutex_unlock(&isys->mutex); 1154 pm_runtime_put(&adev->auxdev.dev); 1155 1156 return ret; 1157} 1158 1159void ipu6_isys_fw_close(struct ipu6_isys *isys) 1160{ 1161 mutex_lock(&isys->mutex); 1162 1163 isys->ref_count--; 1164 if (!isys->ref_count) { 1165 ipu6_fw_isys_close(isys); 1166 if (isys->fwcom) { 1167 isys->need_reset = true; 1168 dev_warn(&isys->adev->auxdev.dev, 1169 "failed to close fw isys\n"); 1170 } 1171 } 1172 1173 mutex_unlock(&isys->mutex); 1174 1175 if (isys->need_reset) 1176 pm_runtime_put_sync(&isys->adev->auxdev.dev); 1177 else 1178 pm_runtime_put(&isys->adev->auxdev.dev); 1179} 1180 1181int ipu6_isys_setup_video(struct ipu6_isys_video *av, 1182 struct media_entity **source_entity, int *nr_queues) 1183{ 1184 const struct ipu6_isys_pixelformat *pfmt = 1185 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0); 1186 struct device *dev = &av->isys->adev->auxdev.dev; 1187 struct v4l2_mbus_frame_desc_entry entry; 1188 struct v4l2_subdev_route *route = NULL; 1189 struct v4l2_subdev_route *r; 1190 struct v4l2_subdev_state *state; 1191 struct ipu6_isys_subdev *asd; 1192 struct v4l2_subdev *remote_sd; 1193 struct media_pipeline *pipeline; 1194 struct media_pad *source_pad, *remote_pad; 1195 int ret = -EINVAL; 1196 1197 *nr_queues = 0; 1198 1199 remote_pad = media_pad_remote_pad_unique(&av->pad); 1200 if (IS_ERR(remote_pad)) { 1201 dev_dbg(dev, "failed to get remote pad\n"); 1202 return PTR_ERR(remote_pad); 1203 } 1204 1205 remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); 1206 asd = to_ipu6_isys_subdev(remote_sd); 1207 source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]); 1208 if (!source_pad) { 1209 dev_dbg(dev, "No external source entity\n"); 1210 return -ENODEV; 1211 } 1212 1213 *source_entity = source_pad->entity; 1214 1215 /* Find the root */ 1216 state = v4l2_subdev_lock_and_get_active_state(remote_sd); 1217 for_each_active_route(&state->routing, r) { 1218 (*nr_queues)++; 1219 1220 if (r->source_pad == remote_pad->index) 1221 route = r; 1222 } 1223 1224 if (!route) { 1225 v4l2_subdev_unlock_state(state); 1226 dev_dbg(dev, "Failed to find route\n"); 1227 return -ENODEV; 1228 } 1229 av->source_stream = route->sink_stream; 1230 v4l2_subdev_unlock_state(state); 1231 1232 ret = ipu6_isys_csi2_get_remote_desc(av->source_stream, 1233 to_ipu6_isys_csi2(asd), 1234 *source_entity, &entry); 1235 if (ret == -ENOIOCTLCMD) { 1236 av->vc = 0; 1237 av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code); 1238 } else if (!ret) { 1239 dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n", 1240 entry.stream, entry.length, entry.bus.csi2.vc, 1241 entry.bus.csi2.dt); 1242 1243 av->vc = entry.bus.csi2.vc; 1244 av->dt = entry.bus.csi2.dt; 1245 } else { 1246 dev_err(dev, "failed to get remote frame desc\n"); 1247 return ret; 1248 } 1249 1250 pipeline = media_entity_pipeline(&av->vdev.entity); 1251 if (!pipeline) 1252 ret = video_device_pipeline_alloc_start(&av->vdev); 1253 else 1254 ret = video_device_pipeline_start(&av->vdev, pipeline); 1255 if (ret < 0) { 1256 dev_dbg(dev, "media pipeline start failed\n"); 1257 return ret; 1258 } 1259 1260 av->stream = ipu6_isys_get_stream(av, asd); 1261 if (!av->stream) { 1262 video_device_pipeline_stop(&av->vdev); 1263 dev_err(dev, "no available stream for firmware\n"); 1264 return -EINVAL; 1265 } 1266 1267 return 0; 1268} 1269 1270/* 1271 * Do everything that's needed to initialise things related to video 1272 * buffer queue, video node, and the related media entity. The caller 1273 * is expected to assign isys field and set the name of the video 1274 * device. 1275 */ 1276int ipu6_isys_video_init(struct ipu6_isys_video *av) 1277{ 1278 struct v4l2_format format = { 1279 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, 1280 .fmt.pix = { 1281 .width = 1920, 1282 .height = 1080, 1283 }, 1284 }; 1285 struct v4l2_format format_meta = { 1286 .type = V4L2_BUF_TYPE_META_CAPTURE, 1287 .fmt.meta = { 1288 .width = 1920, 1289 .height = 4, 1290 }, 1291 }; 1292 int ret; 1293 1294 mutex_init(&av->mutex); 1295 av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC | 1296 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE; 1297 av->vdev.vfl_dir = VFL_DIR_RX; 1298 1299 ret = ipu6_isys_queue_init(&av->aq); 1300 if (ret) 1301 goto out_free_watermark; 1302 1303 av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; 1304 ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad); 1305 if (ret) 1306 goto out_vb2_queue_release; 1307 1308 av->vdev.entity.ops = &entity_ops; 1309 av->vdev.release = video_device_release_empty; 1310 av->vdev.fops = &isys_fops; 1311 av->vdev.v4l2_dev = &av->isys->v4l2_dev; 1312 av->vdev.dev_parent = &av->isys->adev->isp->pdev->dev; 1313 if (!av->vdev.ioctl_ops) 1314 av->vdev.ioctl_ops = &ipu6_v4l2_ioctl_ops; 1315 av->vdev.queue = &av->aq.vbq; 1316 av->vdev.lock = &av->mutex; 1317 1318 __ipu6_isys_vidioc_try_fmt_vid_cap(av, &format); 1319 av->pix_fmt = format.fmt.pix; 1320 __ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta); 1321 av->meta_fmt = format_meta.fmt.meta; 1322 1323 video_set_drvdata(&av->vdev, av); 1324 1325 ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1); 1326 if (ret) 1327 goto out_media_entity_cleanup; 1328 1329 return ret; 1330 1331out_media_entity_cleanup: 1332 vb2_video_unregister_device(&av->vdev); 1333 media_entity_cleanup(&av->vdev.entity); 1334 1335out_vb2_queue_release: 1336 vb2_queue_release(&av->aq.vbq); 1337 1338out_free_watermark: 1339 mutex_destroy(&av->mutex); 1340 1341 return ret; 1342} 1343 1344void ipu6_isys_video_cleanup(struct ipu6_isys_video *av) 1345{ 1346 vb2_video_unregister_device(&av->vdev); 1347 media_entity_cleanup(&av->vdev.entity); 1348 mutex_destroy(&av->mutex); 1349} 1350 1351u32 ipu6_isys_get_format(struct ipu6_isys_video *av) 1352{ 1353 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1354 return av->pix_fmt.pixelformat; 1355 1356 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE) 1357 return av->meta_fmt.dataformat; 1358 1359 return 0; 1360} 1361 1362u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av) 1363{ 1364 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1365 return av->pix_fmt.sizeimage; 1366 1367 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE) 1368 return av->meta_fmt.buffersize; 1369 1370 return 0; 1371} 1372 1373u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av) 1374{ 1375 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1376 return av->pix_fmt.bytesperline; 1377 1378 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE) 1379 return av->meta_fmt.bytesperline; 1380 1381 return 0; 1382} 1383 1384u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av) 1385{ 1386 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1387 return av->pix_fmt.width; 1388 1389 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE) 1390 return av->meta_fmt.width; 1391 1392 return 0; 1393} 1394 1395u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av) 1396{ 1397 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 1398 return av->pix_fmt.height; 1399 1400 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE) 1401 return av->meta_fmt.height; 1402 1403 return 0; 1404}
~/
Read-only file preview.