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 <linux/pm_runtime.h> 8 #include <linux/regmap.h> 9 #include <media/v4l2-device.h> 10 #include <media/v4l2-fwnode.h> 11 12 #include "sun6i_csi.h" 13 #include "sun6i_csi_bridge.h" 14 #include "sun6i_csi_reg.h" 15 16 /* Helpers */ 17 18 void sun6i_csi_bridge_dimensions(struct sun6i_csi_device *csi_dev, 19 unsigned int *width, unsigned int *height) 20 { 21 if (width) 22 *width = csi_dev->bridge.mbus_format.width; 23 if (height) 24 *height = csi_dev->bridge.mbus_format.height; 25 } 26 27 void sun6i_csi_bridge_format(struct sun6i_csi_device *csi_dev, 28 u32 *mbus_code, u32 *field) 29 { 30 if (mbus_code) 31 *mbus_code = csi_dev->bridge.mbus_format.code; 32 if (field) 33 *field = csi_dev->bridge.mbus_format.field; 34 } 35 36 /* Format */ 37 38 static const struct sun6i_csi_bridge_format sun6i_csi_bridge_formats[] = { 39 /* Bayer */ 40 { 41 .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, 42 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 43 }, 44 { 45 .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, 46 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 47 }, 48 { 49 .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, 50 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 51 }, 52 { 53 .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, 54 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 55 }, 56 { 57 .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, 58 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 59 }, 60 { 61 .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, 62 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 63 }, 64 { 65 .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 66 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 67 }, 68 { 69 .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, 70 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 71 }, 72 { 73 .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, 74 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 75 }, 76 { 77 .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, 78 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 79 }, 80 { 81 .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 82 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 83 }, 84 { 85 .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, 86 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 87 }, 88 /* RGB */ 89 { 90 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, 91 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 92 }, 93 { 94 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE, 95 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 96 }, 97 /* YUV422 */ 98 { 99 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, 100 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 101 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, 102 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, 103 }, 104 { 105 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, 106 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 107 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, 108 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, 109 }, 110 { 111 .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, 112 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 113 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, 114 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, 115 }, 116 { 117 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, 118 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 119 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, 120 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, 121 }, 122 { 123 .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, 124 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 125 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, 126 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, 127 }, 128 { 129 .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, 130 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 131 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, 132 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, 133 }, 134 { 135 .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, 136 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 137 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, 138 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, 139 }, 140 { 141 .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, 142 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 143 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, 144 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, 145 }, 146 { 147 .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, 148 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 149 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, 150 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, 151 }, 152 { 153 .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, 154 .input_format = SUN6I_CSI_INPUT_FMT_YUV422, 155 .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, 156 .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, 157 }, 158 /* Compressed */ 159 { 160 .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, 161 .input_format = SUN6I_CSI_INPUT_FMT_RAW, 162 }, 163 }; 164 165 const struct sun6i_csi_bridge_format * 166 sun6i_csi_bridge_format_find(u32 mbus_code) 167 { 168 unsigned int i; 169 170 for (i = 0; i < ARRAY_SIZE(sun6i_csi_bridge_formats); i++) 171 if (sun6i_csi_bridge_formats[i].mbus_code == mbus_code) 172 return &sun6i_csi_bridge_formats[i]; 173 174 return NULL; 175 } 176 177 /* Bridge */ 178 179 static void sun6i_csi_bridge_irq_enable(struct sun6i_csi_device *csi_dev) 180 { 181 struct regmap *regmap = csi_dev->regmap; 182 183 regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 184 SUN6I_CSI_CH_INT_EN_VS | 185 SUN6I_CSI_CH_INT_EN_HB_OF | 186 SUN6I_CSI_CH_INT_EN_FIFO2_OF | 187 SUN6I_CSI_CH_INT_EN_FIFO1_OF | 188 SUN6I_CSI_CH_INT_EN_FIFO0_OF | 189 SUN6I_CSI_CH_INT_EN_FD | 190 SUN6I_CSI_CH_INT_EN_CD); 191 } 192 193 static void sun6i_csi_bridge_irq_disable(struct sun6i_csi_device *csi_dev) 194 { 195 struct regmap *regmap = csi_dev->regmap; 196 197 regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); 198 } 199 200 static void sun6i_csi_bridge_irq_clear(struct sun6i_csi_device *csi_dev) 201 { 202 struct regmap *regmap = csi_dev->regmap; 203 204 regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); 205 regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, 206 SUN6I_CSI_CH_INT_STA_CLEAR); 207 } 208 209 static void sun6i_csi_bridge_enable(struct sun6i_csi_device *csi_dev) 210 { 211 struct regmap *regmap = csi_dev->regmap; 212 213 regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, 214 SUN6I_CSI_EN_CSI_EN); 215 216 regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, 217 SUN6I_CSI_CAP_VCAP_ON); 218 } 219 220 static void sun6i_csi_bridge_disable(struct sun6i_csi_device *csi_dev) 221 { 222 struct regmap *regmap = csi_dev->regmap; 223 224 regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, 0); 225 regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, 0); 226 } 227 228 static void 229 sun6i_csi_bridge_configure_parallel(struct sun6i_csi_device *csi_dev) 230 { 231 struct device *dev = csi_dev->dev; 232 struct regmap *regmap = csi_dev->regmap; 233 struct v4l2_fwnode_endpoint *endpoint = 234 &csi_dev->bridge.source_parallel.endpoint; 235 unsigned char bus_width = endpoint->bus.parallel.bus_width; 236 unsigned int flags = endpoint->bus.parallel.flags; 237 u32 field; 238 u32 value = SUN6I_CSI_IF_CFG_IF_CSI; 239 240 sun6i_csi_bridge_format(csi_dev, NULL, &field); 241 242 if (field == V4L2_FIELD_INTERLACED || 243 field == V4L2_FIELD_INTERLACED_TB || 244 field == V4L2_FIELD_INTERLACED_BT) 245 value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | 246 SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | 247 SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; 248 else 249 value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; 250 251 switch (endpoint->bus_type) { 252 case V4L2_MBUS_PARALLEL: 253 if (bus_width == 16) 254 value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; 255 else 256 value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; 257 258 if (flags & V4L2_MBUS_FIELD_EVEN_LOW) 259 value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; 260 else 261 value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; 262 263 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 264 value |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; 265 else 266 value |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; 267 268 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 269 value |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; 270 else 271 value |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; 272 273 if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 274 value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; 275 else 276 value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; 277 break; 278 case V4L2_MBUS_BT656: 279 if (bus_width == 16) 280 value |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; 281 else 282 value |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; 283 284 if (flags & V4L2_MBUS_FIELD_EVEN_LOW) 285 value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; 286 else 287 value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; 288 289 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 290 value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; 291 else 292 value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; 293 break; 294 default: 295 dev_warn(dev, "unsupported bus type: %d\n", endpoint->bus_type); 296 break; 297 } 298 299 switch (bus_width) { 300 case 8: 301 /* 16-bit YUV formats use a doubled width in 8-bit mode. */ 302 case 16: 303 value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; 304 break; 305 case 10: 306 value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; 307 break; 308 case 12: 309 value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; 310 break; 311 default: 312 dev_warn(dev, "unsupported bus width: %u\n", bus_width); 313 break; 314 } 315 316 regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value); 317 } 318 319 static void 320 sun6i_csi_bridge_configure_mipi_csi2(struct sun6i_csi_device *csi_dev) 321 { 322 struct regmap *regmap = csi_dev->regmap; 323 u32 value = SUN6I_CSI_IF_CFG_IF_MIPI; 324 u32 field; 325 326 sun6i_csi_bridge_format(csi_dev, NULL, &field); 327 328 if (field == V4L2_FIELD_INTERLACED || 329 field == V4L2_FIELD_INTERLACED_TB || 330 field == V4L2_FIELD_INTERLACED_BT) 331 value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED; 332 else 333 value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; 334 335 regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value); 336 } 337 338 static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev) 339 { 340 struct regmap *regmap = csi_dev->regmap; 341 bool capture_streaming = csi_dev->capture.state.streaming; 342 const struct sun6i_csi_bridge_format *bridge_format; 343 const struct sun6i_csi_capture_format *capture_format; 344 u32 mbus_code, field, pixelformat; 345 u8 input_format, input_yuv_seq, output_format; 346 u32 value = 0; 347 348 sun6i_csi_bridge_format(csi_dev, &mbus_code, &field); 349 350 bridge_format = sun6i_csi_bridge_format_find(mbus_code); 351 if (WARN_ON(!bridge_format)) 352 return; 353 354 input_format = bridge_format->input_format; 355 input_yuv_seq = bridge_format->input_yuv_seq; 356 357 if (capture_streaming) { 358 sun6i_csi_capture_format(csi_dev, &pixelformat, NULL); 359 360 capture_format = sun6i_csi_capture_format_find(pixelformat); 361 if (WARN_ON(!capture_format)) 362 return; 363 364 if (capture_format->input_format_raw) 365 input_format = SUN6I_CSI_INPUT_FMT_RAW; 366 367 if (capture_format->input_yuv_seq_invert) 368 input_yuv_seq = bridge_format->input_yuv_seq_invert; 369 370 if (field == V4L2_FIELD_INTERLACED || 371 field == V4L2_FIELD_INTERLACED_TB || 372 field == V4L2_FIELD_INTERLACED_BT) 373 output_format = capture_format->output_format_field; 374 else 375 output_format = capture_format->output_format_frame; 376 377 value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format); 378 } 379 380 value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format); 381 value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq); 382 383 if (field == V4L2_FIELD_TOP) 384 value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; 385 else if (field == V4L2_FIELD_BOTTOM) 386 value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; 387 else 388 value |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; 389 390 regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value); 391 } 392 393 static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev, 394 struct sun6i_csi_bridge_source *source) 395 { 396 struct sun6i_csi_bridge *bridge = &csi_dev->bridge; 397 398 if (source == &bridge->source_parallel) 399 sun6i_csi_bridge_configure_parallel(csi_dev); 400 else 401 sun6i_csi_bridge_configure_mipi_csi2(csi_dev); 402 403 sun6i_csi_bridge_configure_format(csi_dev); 404 } 405 406 /* V4L2 Subdev */ 407 408 static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) 409 { 410 struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); 411 struct sun6i_csi_bridge *bridge = &csi_dev->bridge; 412 struct media_pad *local_pad = &bridge->pads[SUN6I_CSI_BRIDGE_PAD_SINK]; 413 bool capture_streaming = csi_dev->capture.state.streaming; 414 struct device *dev = csi_dev->dev; 415 struct sun6i_csi_bridge_source *source; 416 struct v4l2_subdev *source_subdev; 417 struct media_pad *remote_pad; 418 int ret; 419 420 /* Source */ 421 422 remote_pad = media_pad_remote_pad_unique(local_pad); 423 if (IS_ERR(remote_pad)) { 424 dev_err(dev, 425 "zero or more than a single source connected to the bridge\n"); 426 return PTR_ERR(remote_pad); 427 } 428 429 source_subdev = media_entity_to_v4l2_subdev(remote_pad->entity); 430 431 if (source_subdev == bridge->source_parallel.subdev) 432 source = &bridge->source_parallel; 433 else 434 source = &bridge->source_mipi_csi2; 435 436 if (!on) { 437 v4l2_subdev_call(source_subdev, video, s_stream, 0); 438 ret = 0; 439 goto disable; 440 } 441 442 /* PM */ 443 444 ret = pm_runtime_resume_and_get(dev); 445 if (ret < 0) 446 return ret; 447 448 /* Clear */ 449 450 sun6i_csi_bridge_irq_clear(csi_dev); 451 452 /* Configure */ 453 454 sun6i_csi_bridge_configure(csi_dev, source); 455 456 if (capture_streaming) 457 sun6i_csi_capture_configure(csi_dev); 458 459 /* State Update */ 460 461 if (capture_streaming) 462 sun6i_csi_capture_state_update(csi_dev); 463 464 /* Enable */ 465 466 if (capture_streaming) 467 sun6i_csi_bridge_irq_enable(csi_dev); 468 469 sun6i_csi_bridge_enable(csi_dev); 470 471 ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); 472 if (ret && ret != -ENOIOCTLCMD) 473 goto disable; 474 475 return 0; 476 477 disable: 478 if (capture_streaming) 479 sun6i_csi_bridge_irq_disable(csi_dev); 480 481 sun6i_csi_bridge_disable(csi_dev); 482 483 pm_runtime_put(dev); 484 485 return ret; 486 } 487 488 static const struct v4l2_subdev_video_ops sun6i_csi_bridge_video_ops = { 489 .s_stream = sun6i_csi_bridge_s_stream, 490 }; 491 492 static void 493 sun6i_csi_bridge_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) 494 { 495 if (!sun6i_csi_bridge_format_find(mbus_format->code)) 496 mbus_format->code = sun6i_csi_bridge_formats[0].mbus_code; 497 498 mbus_format->field = V4L2_FIELD_NONE; 499 mbus_format->colorspace = V4L2_COLORSPACE_RAW; 500 mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT; 501 mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; 502 } 503 504 static int sun6i_csi_bridge_init_state(struct v4l2_subdev *subdev, 505 struct v4l2_subdev_state *state) 506 { 507 struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); 508 unsigned int pad = SUN6I_CSI_BRIDGE_PAD_SINK; 509 struct v4l2_mbus_framefmt *mbus_format = 510 v4l2_subdev_state_get_format(state, pad); 511 struct mutex *lock = &csi_dev->bridge.lock; 512 513 mutex_lock(lock); 514 515 mbus_format->code = sun6i_csi_bridge_formats[0].mbus_code; 516 mbus_format->width = 1280; 517 mbus_format->height = 720; 518 519 sun6i_csi_bridge_mbus_format_prepare(mbus_format); 520 521 mutex_unlock(lock); 522 523 return 0; 524 } 525 526 static int 527 sun6i_csi_bridge_enum_mbus_code(struct v4l2_subdev *subdev, 528 struct v4l2_subdev_state *state, 529 struct v4l2_subdev_mbus_code_enum *code_enum) 530 { 531 if (code_enum->index >= ARRAY_SIZE(sun6i_csi_bridge_formats)) 532 return -EINVAL; 533 534 code_enum->code = sun6i_csi_bridge_formats[code_enum->index].mbus_code; 535 536 return 0; 537 } 538 539 static int sun6i_csi_bridge_get_fmt(struct v4l2_subdev *subdev, 540 struct v4l2_subdev_state *state, 541 struct v4l2_subdev_format *format) 542 { 543 struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); 544 struct v4l2_mbus_framefmt *mbus_format = &format->format; 545 struct mutex *lock = &csi_dev->bridge.lock; 546 547 mutex_lock(lock); 548 549 if (format->which == V4L2_SUBDEV_FORMAT_TRY) 550 *mbus_format = *v4l2_subdev_state_get_format(state, 551 format->pad); 552 else 553 *mbus_format = csi_dev->bridge.mbus_format; 554 555 mutex_unlock(lock); 556 557 return 0; 558 } 559 560 static int sun6i_csi_bridge_set_fmt(struct v4l2_subdev *subdev, 561 struct v4l2_subdev_state *state, 562 struct v4l2_subdev_format *format) 563 { 564 struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); 565 struct v4l2_mbus_framefmt *mbus_format = &format->format; 566 struct mutex *lock = &csi_dev->bridge.lock; 567 568 mutex_lock(lock); 569 570 sun6i_csi_bridge_mbus_format_prepare(mbus_format); 571 572 if (format->which == V4L2_SUBDEV_FORMAT_TRY) 573 *v4l2_subdev_state_get_format(state, format->pad) = 574 *mbus_format; 575 else 576 csi_dev->bridge.mbus_format = *mbus_format; 577 578 mutex_unlock(lock); 579 580 return 0; 581 } 582 583 static const struct v4l2_subdev_pad_ops sun6i_csi_bridge_pad_ops = { 584 .enum_mbus_code = sun6i_csi_bridge_enum_mbus_code, 585 .get_fmt = sun6i_csi_bridge_get_fmt, 586 .set_fmt = sun6i_csi_bridge_set_fmt, 587 }; 588 589 static const struct v4l2_subdev_ops sun6i_csi_bridge_subdev_ops = { 590 .video = &sun6i_csi_bridge_video_ops, 591 .pad = &sun6i_csi_bridge_pad_ops, 592 }; 593 594 static const struct v4l2_subdev_internal_ops sun6i_csi_bridge_internal_ops = { 595 .init_state = sun6i_csi_bridge_init_state, 596 }; 597 598 /* Media Entity */ 599 600 static const struct media_entity_operations sun6i_csi_bridge_entity_ops = { 601 .link_validate = v4l2_subdev_link_validate, 602 }; 603 604 /* V4L2 Async */ 605 606 static int sun6i_csi_bridge_link(struct sun6i_csi_device *csi_dev, 607 int sink_pad_index, 608 struct v4l2_subdev *remote_subdev, 609 bool enabled) 610 { 611 struct device *dev = csi_dev->dev; 612 struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; 613 struct media_entity *sink_entity = &subdev->entity; 614 struct media_entity *source_entity = &remote_subdev->entity; 615 int source_pad_index; 616 int ret; 617 618 /* Get the first remote source pad. */ 619 ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode, 620 MEDIA_PAD_FL_SOURCE); 621 if (ret < 0) { 622 dev_err(dev, "missing source pad in external entity %s\n", 623 source_entity->name); 624 return -EINVAL; 625 } 626 627 source_pad_index = ret; 628 629 dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name, 630 source_pad_index, sink_entity->name, sink_pad_index); 631 632 ret = media_create_pad_link(source_entity, source_pad_index, 633 sink_entity, sink_pad_index, 634 enabled ? MEDIA_LNK_FL_ENABLED : 0); 635 if (ret < 0) { 636 dev_err(dev, "failed to create %s:%u -> %s:%u link\n", 637 source_entity->name, source_pad_index, 638 sink_entity->name, sink_pad_index); 639 return ret; 640 } 641 642 return 0; 643 } 644 645 static int 646 sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier, 647 struct v4l2_subdev *remote_subdev, 648 struct v4l2_async_connection *async_subdev) 649 { 650 struct sun6i_csi_device *csi_dev = 651 container_of(notifier, struct sun6i_csi_device, 652 bridge.notifier); 653 struct sun6i_csi_bridge_async_subdev *bridge_async_subdev = 654 container_of(async_subdev, struct sun6i_csi_bridge_async_subdev, 655 async_subdev); 656 struct sun6i_csi_bridge *bridge = &csi_dev->bridge; 657 struct sun6i_csi_bridge_source *source = bridge_async_subdev->source; 658 bool enabled = false; 659 int ret; 660 661 switch (source->endpoint.base.port) { 662 case SUN6I_CSI_PORT_PARALLEL: 663 enabled = true; 664 break; 665 case SUN6I_CSI_PORT_MIPI_CSI2: 666 enabled = !bridge->source_parallel.expected; 667 break; 668 default: 669 return -EINVAL; 670 } 671 672 source->subdev = remote_subdev; 673 674 if (csi_dev->isp_available) { 675 /* 676 * Hook to the first available remote subdev to get v4l2 and 677 * media devices and register the capture device then. 678 */ 679 ret = sun6i_csi_isp_complete(csi_dev, remote_subdev->v4l2_dev); 680 if (ret) 681 return ret; 682 } 683 684 return sun6i_csi_bridge_link(csi_dev, SUN6I_CSI_BRIDGE_PAD_SINK, 685 remote_subdev, enabled); 686 } 687 688 static int 689 sun6i_csi_bridge_notifier_complete(struct v4l2_async_notifier *notifier) 690 { 691 struct sun6i_csi_device *csi_dev = 692 container_of(notifier, struct sun6i_csi_device, 693 bridge.notifier); 694 struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; 695 696 if (csi_dev->isp_available) 697 return 0; 698 699 return v4l2_device_register_subdev_nodes(v4l2_dev); 700 } 701 702 static const struct v4l2_async_notifier_operations 703 sun6i_csi_bridge_notifier_ops = { 704 .bound = sun6i_csi_bridge_notifier_bound, 705 .complete = sun6i_csi_bridge_notifier_complete, 706 }; 707 708 /* Bridge */ 709 710 static int sun6i_csi_bridge_source_setup(struct sun6i_csi_device *csi_dev, 711 struct sun6i_csi_bridge_source *source, 712 u32 port, 713 enum v4l2_mbus_type *bus_types) 714 { 715 struct device *dev = csi_dev->dev; 716 struct v4l2_async_notifier *notifier = &csi_dev->bridge.notifier; 717 struct v4l2_fwnode_endpoint *endpoint = &source->endpoint; 718 struct sun6i_csi_bridge_async_subdev *bridge_async_subdev; 719 struct fwnode_handle *handle; 720 int ret; 721 722 handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), port, 0, 0); 723 if (!handle) 724 return -ENODEV; 725 726 ret = v4l2_fwnode_endpoint_parse(handle, endpoint); 727 if (ret) 728 goto complete; 729 730 if (bus_types) { 731 bool valid = false; 732 unsigned int i; 733 734 for (i = 0; bus_types[i] != V4L2_MBUS_INVALID; i++) { 735 if (endpoint->bus_type == bus_types[i]) { 736 valid = true; 737 break; 738 } 739 } 740 741 if (!valid) { 742 dev_err(dev, "unsupported bus type for port %d\n", 743 port); 744 ret = -EINVAL; 745 goto complete; 746 } 747 } 748 749 bridge_async_subdev = 750 v4l2_async_nf_add_fwnode_remote(notifier, handle, 751 struct 752 sun6i_csi_bridge_async_subdev); 753 if (IS_ERR(bridge_async_subdev)) { 754 ret = PTR_ERR(bridge_async_subdev); 755 goto complete; 756 } 757 758 bridge_async_subdev->source = source; 759 760 source->expected = true; 761 762 complete: 763 fwnode_handle_put(handle); 764 765 return ret; 766 } 767 768 int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) 769 { 770 struct device *dev = csi_dev->dev; 771 struct sun6i_csi_bridge *bridge = &csi_dev->bridge; 772 struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev; 773 struct v4l2_subdev *subdev = &bridge->subdev; 774 struct v4l2_async_notifier *notifier = &bridge->notifier; 775 struct media_pad *pads = bridge->pads; 776 enum v4l2_mbus_type parallel_mbus_types[] = { 777 V4L2_MBUS_PARALLEL, 778 V4L2_MBUS_BT656, 779 V4L2_MBUS_INVALID 780 }; 781 int ret; 782 783 mutex_init(&bridge->lock); 784 785 /* V4L2 Subdev */ 786 787 v4l2_subdev_init(subdev, &sun6i_csi_bridge_subdev_ops); 788 subdev->internal_ops = &sun6i_csi_bridge_internal_ops; 789 strscpy(subdev->name, SUN6I_CSI_BRIDGE_NAME, sizeof(subdev->name)); 790 subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 791 subdev->owner = THIS_MODULE; 792 subdev->dev = dev; 793 794 v4l2_set_subdevdata(subdev, csi_dev); 795 796 /* Media Entity */ 797 798 subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 799 subdev->entity.ops = &sun6i_csi_bridge_entity_ops; 800 801 /* Media Pads */ 802 803 pads[SUN6I_CSI_BRIDGE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 804 pads[SUN6I_CSI_BRIDGE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE | 805 MEDIA_PAD_FL_MUST_CONNECT; 806 807 ret = media_entity_pads_init(&subdev->entity, 808 SUN6I_CSI_BRIDGE_PAD_COUNT, pads); 809 if (ret < 0) 810 return ret; 811 812 /* V4L2 Subdev */ 813 814 if (csi_dev->isp_available) 815 ret = v4l2_async_register_subdev(subdev); 816 else 817 ret = v4l2_device_register_subdev(v4l2_dev, subdev); 818 819 if (ret) { 820 dev_err(dev, "failed to register v4l2 subdev: %d\n", ret); 821 goto error_media_entity; 822 } 823 824 /* V4L2 Async */ 825 826 if (csi_dev->isp_available) 827 v4l2_async_subdev_nf_init(notifier, subdev); 828 else 829 v4l2_async_nf_init(notifier, v4l2_dev); 830 notifier->ops = &sun6i_csi_bridge_notifier_ops; 831 832 sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel, 833 SUN6I_CSI_PORT_PARALLEL, 834 parallel_mbus_types); 835 sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_mipi_csi2, 836 SUN6I_CSI_PORT_MIPI_CSI2, NULL); 837 838 ret = v4l2_async_nf_register(notifier); 839 if (ret) { 840 dev_err(dev, "failed to register v4l2 async notifier: %d\n", 841 ret); 842 goto error_v4l2_async_notifier; 843 } 844 845 return 0; 846 847 error_v4l2_async_notifier: 848 v4l2_async_nf_cleanup(notifier); 849 850 if (csi_dev->isp_available) 851 v4l2_async_unregister_subdev(subdev); 852 else 853 v4l2_device_unregister_subdev(subdev); 854 855 error_media_entity: 856 media_entity_cleanup(&subdev->entity); 857 858 return ret; 859 } 860 861 void sun6i_csi_bridge_cleanup(struct sun6i_csi_device *csi_dev) 862 { 863 struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; 864 struct v4l2_async_notifier *notifier = &csi_dev->bridge.notifier; 865 866 v4l2_async_nf_unregister(notifier); 867 v4l2_async_nf_cleanup(notifier); 868 869 v4l2_device_unregister_subdev(subdev); 870 871 media_entity_cleanup(&subdev->entity); 872 } 873