Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: rockchip: rkcif: add support for rk3568 vicap mipi capture

The RK3568 Video Capture (VICAP) unit features a MIPI CSI-2 capture
interface. Add support for the MIPI capture interface in general
and for the RK3568 VICAP MIPI capture in particular.

Signed-off-by: Michael Riesch <michael.riesch@wolfvision.net>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: Mehdi Djait <mehdi.djait@linux.intel.com>
Signed-off-by: Michael Riesch <michael.riesch@collabora.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>

authored by

Michael Riesch and committed by
Hans Verkuil
1f2353f5 c348d671

+864
+1
drivers/media/platform/rockchip/rkcif/Makefile
··· 2 2 obj-$(CONFIG_VIDEO_ROCKCHIP_CIF) += rockchip-cif.o 3 3 4 4 rockchip-cif-objs += rkcif-capture-dvp.o 5 + rockchip-cif-objs += rkcif-capture-mipi.o 5 6 rockchip-cif-objs += rkcif-dev.o 6 7 rockchip-cif-objs += rkcif-interface.o 7 8 rockchip-cif-objs += rkcif-stream.o
+777
drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Rockchip Camera Interface (CIF) Driver 4 + * 5 + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. 6 + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> 7 + * Copyright (C) 2025 Collabora, Ltd. 8 + */ 9 + 10 + #include <linux/interrupt.h> 11 + 12 + #include <media/mipi-csi2.h> 13 + #include <media/v4l2-common.h> 14 + #include <media/v4l2-event.h> 15 + #include <media/v4l2-fh.h> 16 + #include <media/v4l2-fwnode.h> 17 + #include <media/v4l2-ioctl.h> 18 + #include <media/v4l2-mc.h> 19 + #include <media/v4l2-subdev.h> 20 + 21 + #include "rkcif-capture-mipi.h" 22 + #include "rkcif-common.h" 23 + #include "rkcif-interface.h" 24 + #include "rkcif-regs.h" 25 + #include "rkcif-stream.h" 26 + 27 + #define RK3568_MIPI_CTRL0_HIGH_ALIGN BIT(31) 28 + #define RK3568_MIPI_CTRL0_UV_SWAP_EN BIT(7) 29 + #define RK3568_MIPI_CTRL0_COMPACT_EN BIT(6) 30 + #define RK3568_MIPI_CTRL0_CROP_EN BIT(5) 31 + #define RK3568_MIPI_CTRL0_WRDDR(type) ((type) << 1) 32 + 33 + #define RKCIF_MIPI_CTRL0_DT_ID(id) ((id) << 10) 34 + #define RKCIF_MIPI_CTRL0_VC_ID(id) ((id) << 8) 35 + #define RKCIF_MIPI_CTRL0_CAP_EN BIT(0) 36 + 37 + #define RKCIF_MIPI_INT_FRAME0_END(id) BIT(8 + (id) * 2 + 0) 38 + #define RKCIF_MIPI_INT_FRAME1_END(id) BIT(8 + (id) * 2 + 1) 39 + 40 + static const struct rkcif_output_fmt mipi_out_fmts[] = { 41 + /* YUV formats */ 42 + { 43 + .fourcc = V4L2_PIX_FMT_YUYV, 44 + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, 45 + .depth = 16, 46 + .cplanes = 1, 47 + .mipi = { 48 + .dt = MIPI_CSI2_DT_YUV422_8B, 49 + .type = RKCIF_MIPI_TYPE_RAW8, 50 + }, 51 + }, 52 + { 53 + .fourcc = V4L2_PIX_FMT_UYVY, 54 + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, 55 + .depth = 16, 56 + .cplanes = 1, 57 + .mipi = { 58 + .dt = MIPI_CSI2_DT_YUV422_8B, 59 + .type = RKCIF_MIPI_TYPE_RAW8, 60 + }, 61 + }, 62 + { 63 + .fourcc = V4L2_PIX_FMT_YVYU, 64 + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, 65 + .depth = 16, 66 + .cplanes = 1, 67 + .mipi = { 68 + .dt = MIPI_CSI2_DT_YUV422_8B, 69 + .type = RKCIF_MIPI_TYPE_RAW8, 70 + }, 71 + }, 72 + { 73 + .fourcc = V4L2_PIX_FMT_VYUY, 74 + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, 75 + .depth = 16, 76 + .cplanes = 1, 77 + .mipi = { 78 + .dt = MIPI_CSI2_DT_YUV422_8B, 79 + .type = RKCIF_MIPI_TYPE_RAW8, 80 + }, 81 + }, 82 + /* RGB formats */ 83 + { 84 + .fourcc = V4L2_PIX_FMT_RGB24, 85 + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, 86 + .depth = 24, 87 + .cplanes = 1, 88 + .mipi = { 89 + .dt = MIPI_CSI2_DT_RGB888, 90 + .type = RKCIF_MIPI_TYPE_RGB888, 91 + }, 92 + }, 93 + { 94 + .fourcc = V4L2_PIX_FMT_BGR24, 95 + .mbus_code = MEDIA_BUS_FMT_BGR888_1X24, 96 + .depth = 24, 97 + .cplanes = 1, 98 + .mipi = { 99 + .dt = MIPI_CSI2_DT_RGB888, 100 + .type = RKCIF_MIPI_TYPE_RGB888, 101 + }, 102 + }, 103 + /* Bayer formats */ 104 + { 105 + .fourcc = V4L2_PIX_FMT_SBGGR8, 106 + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, 107 + .depth = 8, 108 + .cplanes = 1, 109 + .mipi = { 110 + .dt = MIPI_CSI2_DT_RAW8, 111 + .type = RKCIF_MIPI_TYPE_RAW8, 112 + }, 113 + }, 114 + { 115 + .fourcc = V4L2_PIX_FMT_SGBRG8, 116 + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, 117 + .depth = 8, 118 + .cplanes = 1, 119 + .mipi = { 120 + .dt = MIPI_CSI2_DT_RAW8, 121 + .type = RKCIF_MIPI_TYPE_RAW8, 122 + }, 123 + }, 124 + { 125 + .fourcc = V4L2_PIX_FMT_SGRBG8, 126 + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, 127 + .depth = 8, 128 + .cplanes = 1, 129 + .mipi = { 130 + .dt = MIPI_CSI2_DT_RAW8, 131 + .type = RKCIF_MIPI_TYPE_RAW8, 132 + }, 133 + }, 134 + { 135 + .fourcc = V4L2_PIX_FMT_SRGGB8, 136 + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, 137 + .depth = 8, 138 + .cplanes = 1, 139 + .mipi = { 140 + .dt = MIPI_CSI2_DT_RAW8, 141 + .type = RKCIF_MIPI_TYPE_RAW8, 142 + }, 143 + }, 144 + { 145 + .fourcc = V4L2_PIX_FMT_SBGGR10, 146 + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, 147 + .depth = 10, 148 + .cplanes = 1, 149 + .mipi = { 150 + .dt = MIPI_CSI2_DT_RAW10, 151 + .type = RKCIF_MIPI_TYPE_RAW10, 152 + }, 153 + }, 154 + { 155 + .fourcc = V4L2_PIX_FMT_SBGGR10P, 156 + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, 157 + .depth = 10, 158 + .cplanes = 1, 159 + .mipi = { 160 + .dt = MIPI_CSI2_DT_RAW10, 161 + .compact = true, 162 + .type = RKCIF_MIPI_TYPE_RAW10, 163 + }, 164 + }, 165 + { 166 + .fourcc = V4L2_PIX_FMT_SGBRG10, 167 + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, 168 + .depth = 10, 169 + .cplanes = 1, 170 + .mipi = { 171 + .dt = MIPI_CSI2_DT_RAW10, 172 + .type = RKCIF_MIPI_TYPE_RAW10, 173 + }, 174 + }, 175 + { 176 + .fourcc = V4L2_PIX_FMT_SGBRG10P, 177 + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, 178 + .depth = 10, 179 + .cplanes = 1, 180 + .mipi = { 181 + .dt = MIPI_CSI2_DT_RAW10, 182 + .compact = true, 183 + .type = RKCIF_MIPI_TYPE_RAW10, 184 + }, 185 + }, 186 + { 187 + .fourcc = V4L2_PIX_FMT_SGRBG10, 188 + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 189 + .depth = 10, 190 + .cplanes = 1, 191 + .mipi = { 192 + .dt = MIPI_CSI2_DT_RAW10, 193 + .type = RKCIF_MIPI_TYPE_RAW10, 194 + }, 195 + }, 196 + { 197 + .fourcc = V4L2_PIX_FMT_SGRBG10P, 198 + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 199 + .depth = 10, 200 + .cplanes = 1, 201 + .mipi = { 202 + .dt = MIPI_CSI2_DT_RAW10, 203 + .compact = true, 204 + .type = RKCIF_MIPI_TYPE_RAW10, 205 + }, 206 + }, 207 + { 208 + .fourcc = V4L2_PIX_FMT_SRGGB10, 209 + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, 210 + .depth = 10, 211 + .cplanes = 1, 212 + .mipi = { 213 + .dt = MIPI_CSI2_DT_RAW10, 214 + .type = RKCIF_MIPI_TYPE_RAW10, 215 + }, 216 + }, 217 + { 218 + .fourcc = V4L2_PIX_FMT_SRGGB10P, 219 + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, 220 + .depth = 10, 221 + .cplanes = 1, 222 + .mipi = { 223 + .dt = MIPI_CSI2_DT_RAW10, 224 + .compact = true, 225 + .type = RKCIF_MIPI_TYPE_RAW10, 226 + }, 227 + }, 228 + { 229 + .fourcc = V4L2_PIX_FMT_SBGGR12, 230 + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, 231 + .depth = 12, 232 + .cplanes = 1, 233 + .mipi = { 234 + .dt = MIPI_CSI2_DT_RAW12, 235 + .type = RKCIF_MIPI_TYPE_RAW12, 236 + }, 237 + }, 238 + { 239 + .fourcc = V4L2_PIX_FMT_SBGGR12P, 240 + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, 241 + .depth = 12, 242 + .cplanes = 1, 243 + .mipi = { 244 + .dt = MIPI_CSI2_DT_RAW12, 245 + .compact = true, 246 + .type = RKCIF_MIPI_TYPE_RAW12, 247 + }, 248 + }, 249 + { 250 + .fourcc = V4L2_PIX_FMT_SGBRG12, 251 + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, 252 + .depth = 12, 253 + .cplanes = 1, 254 + .mipi = { 255 + .dt = MIPI_CSI2_DT_RAW12, 256 + .type = RKCIF_MIPI_TYPE_RAW12, 257 + }, 258 + }, 259 + { 260 + .fourcc = V4L2_PIX_FMT_SGBRG12P, 261 + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, 262 + .depth = 12, 263 + .cplanes = 1, 264 + .mipi = { 265 + .dt = MIPI_CSI2_DT_RAW12, 266 + .compact = true, 267 + .type = RKCIF_MIPI_TYPE_RAW12, 268 + }, 269 + }, 270 + { 271 + .fourcc = V4L2_PIX_FMT_SGRBG12, 272 + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 273 + .depth = 12, 274 + .cplanes = 1, 275 + .mipi = { 276 + .dt = MIPI_CSI2_DT_RAW12, 277 + .type = RKCIF_MIPI_TYPE_RAW12, 278 + }, 279 + }, 280 + { 281 + .fourcc = V4L2_PIX_FMT_SGRBG12P, 282 + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 283 + .depth = 12, 284 + .cplanes = 1, 285 + .mipi = { 286 + .dt = MIPI_CSI2_DT_RAW12, 287 + .compact = true, 288 + .type = RKCIF_MIPI_TYPE_RAW12, 289 + }, 290 + }, 291 + { 292 + .fourcc = V4L2_PIX_FMT_SRGGB12, 293 + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, 294 + .depth = 12, 295 + .cplanes = 1, 296 + .mipi = { 297 + .dt = MIPI_CSI2_DT_RAW12, 298 + .type = RKCIF_MIPI_TYPE_RAW12, 299 + }, 300 + }, 301 + { 302 + .fourcc = V4L2_PIX_FMT_SRGGB12P, 303 + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, 304 + .depth = 12, 305 + .cplanes = 1, 306 + .mipi = { 307 + .dt = MIPI_CSI2_DT_RAW12, 308 + .compact = true, 309 + .type = RKCIF_MIPI_TYPE_RAW12, 310 + }, 311 + }, 312 + }; 313 + 314 + static const struct rkcif_input_fmt mipi_in_fmts[] = { 315 + /* YUV formats */ 316 + { 317 + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, 318 + }, 319 + { 320 + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, 321 + }, 322 + { 323 + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, 324 + }, 325 + { 326 + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, 327 + }, 328 + /* RGB formats */ 329 + { 330 + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, 331 + }, 332 + { 333 + .mbus_code = MEDIA_BUS_FMT_BGR888_1X24, 334 + }, 335 + /* Bayer formats */ 336 + { 337 + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, 338 + }, 339 + { 340 + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, 341 + }, 342 + { 343 + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, 344 + }, 345 + { 346 + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, 347 + }, 348 + { 349 + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, 350 + }, 351 + { 352 + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, 353 + }, 354 + { 355 + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 356 + }, 357 + { 358 + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, 359 + }, 360 + { 361 + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, 362 + }, 363 + { 364 + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, 365 + }, 366 + { 367 + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 368 + }, 369 + { 370 + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, 371 + }, 372 + }; 373 + 374 + static u32 375 + rkcif_rk3568_mipi_ctrl0(struct rkcif_stream *stream, 376 + const struct rkcif_output_fmt *active_out_fmt) 377 + { 378 + u32 ctrl0 = 0; 379 + 380 + ctrl0 |= RKCIF_MIPI_CTRL0_DT_ID(active_out_fmt->mipi.dt); 381 + ctrl0 |= RKCIF_MIPI_CTRL0_CAP_EN; 382 + ctrl0 |= RK3568_MIPI_CTRL0_CROP_EN; 383 + 384 + if (active_out_fmt->mipi.compact) 385 + ctrl0 |= RK3568_MIPI_CTRL0_COMPACT_EN; 386 + 387 + switch (active_out_fmt->mipi.type) { 388 + case RKCIF_MIPI_TYPE_RAW8: 389 + break; 390 + case RKCIF_MIPI_TYPE_RAW10: 391 + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x1); 392 + break; 393 + case RKCIF_MIPI_TYPE_RAW12: 394 + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x2); 395 + break; 396 + case RKCIF_MIPI_TYPE_RGB888: 397 + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x3); 398 + break; 399 + case RKCIF_MIPI_TYPE_YUV422SP: 400 + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x4); 401 + break; 402 + case RKCIF_MIPI_TYPE_YUV420SP: 403 + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x5); 404 + break; 405 + case RKCIF_MIPI_TYPE_YUV400: 406 + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x6); 407 + break; 408 + default: 409 + break; 410 + } 411 + 412 + return ctrl0; 413 + } 414 + 415 + const struct rkcif_mipi_match_data rkcif_rk3568_vicap_mipi_match_data = { 416 + .mipi_num = 1, 417 + .mipi_ctrl0 = rkcif_rk3568_mipi_ctrl0, 418 + .regs = { 419 + [RKCIF_MIPI_CTRL] = 0x20, 420 + [RKCIF_MIPI_INTEN] = 0xa4, 421 + [RKCIF_MIPI_INTSTAT] = 0xa8, 422 + }, 423 + .regs_id = { 424 + [RKCIF_ID0] = { 425 + [RKCIF_MIPI_CTRL0] = 0x00, 426 + [RKCIF_MIPI_CTRL1] = 0x04, 427 + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x24, 428 + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x2c, 429 + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x34, 430 + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x3c, 431 + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x28, 432 + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x30, 433 + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x38, 434 + [RKCIF_MIPI_FRAME1_VLW_UV] = 0x40, 435 + [RKCIF_MIPI_CROP_START] = 0xbc, 436 + }, 437 + [RKCIF_ID1] = { 438 + [RKCIF_MIPI_CTRL0] = 0x08, 439 + [RKCIF_MIPI_CTRL1] = 0x0c, 440 + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x44, 441 + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x4c, 442 + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x54, 443 + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x5c, 444 + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x48, 445 + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x50, 446 + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x58, 447 + [RKCIF_MIPI_FRAME1_VLW_UV] = 0x60, 448 + [RKCIF_MIPI_CROP_START] = 0xc0, 449 + }, 450 + [RKCIF_ID2] = { 451 + [RKCIF_MIPI_CTRL0] = 0x10, 452 + [RKCIF_MIPI_CTRL1] = 0x14, 453 + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x64, 454 + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x6c, 455 + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x74, 456 + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x7c, 457 + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x68, 458 + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x70, 459 + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x78, 460 + [RKCIF_MIPI_FRAME1_VLW_UV] = 0x80, 461 + [RKCIF_MIPI_CROP_START] = 0xc4, 462 + }, 463 + [RKCIF_ID3] = { 464 + [RKCIF_MIPI_CTRL0] = 0x18, 465 + [RKCIF_MIPI_CTRL1] = 0x1c, 466 + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x84, 467 + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x8c, 468 + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x94, 469 + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x9c, 470 + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x88, 471 + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x90, 472 + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x98, 473 + [RKCIF_MIPI_FRAME1_VLW_UV] = 0xa0, 474 + [RKCIF_MIPI_CROP_START] = 0xc8, 475 + }, 476 + }, 477 + .blocks = { 478 + { 479 + .offset = 0x80, 480 + }, 481 + }, 482 + }; 483 + 484 + static inline unsigned int rkcif_mipi_get_reg(struct rkcif_interface *interface, 485 + unsigned int index) 486 + { 487 + struct rkcif_device *rkcif = interface->rkcif; 488 + unsigned int block, offset, reg; 489 + 490 + block = interface->index - RKCIF_MIPI_BASE; 491 + 492 + if (WARN_ON_ONCE(block > RKCIF_MIPI_MAX - RKCIF_MIPI_BASE) || 493 + WARN_ON_ONCE(index > RKCIF_MIPI_REGISTER_MAX)) 494 + return RKCIF_REGISTER_NOTSUPPORTED; 495 + 496 + offset = rkcif->match_data->mipi->blocks[block].offset; 497 + reg = rkcif->match_data->mipi->regs[index]; 498 + if (reg == RKCIF_REGISTER_NOTSUPPORTED) 499 + return reg; 500 + 501 + return offset + reg; 502 + } 503 + 504 + static inline unsigned int rkcif_mipi_id_get_reg(struct rkcif_stream *stream, 505 + unsigned int index) 506 + { 507 + struct rkcif_device *rkcif = stream->rkcif; 508 + unsigned int block, id, offset, reg; 509 + 510 + block = stream->interface->index - RKCIF_MIPI_BASE; 511 + id = stream->id; 512 + 513 + if (WARN_ON_ONCE(block > RKCIF_MIPI_MAX - RKCIF_MIPI_BASE) || 514 + WARN_ON_ONCE(id > RKCIF_ID_MAX) || 515 + WARN_ON_ONCE(index > RKCIF_MIPI_ID_REGISTER_MAX)) 516 + return RKCIF_REGISTER_NOTSUPPORTED; 517 + 518 + offset = rkcif->match_data->mipi->blocks[block].offset; 519 + reg = rkcif->match_data->mipi->regs_id[id][index]; 520 + if (reg == RKCIF_REGISTER_NOTSUPPORTED) 521 + return reg; 522 + 523 + return offset + reg; 524 + } 525 + 526 + static inline __maybe_unused void 527 + rkcif_mipi_write(struct rkcif_interface *interface, unsigned int index, u32 val) 528 + { 529 + unsigned int addr = rkcif_mipi_get_reg(interface, index); 530 + 531 + if (addr == RKCIF_REGISTER_NOTSUPPORTED) 532 + return; 533 + 534 + writel(val, interface->rkcif->base_addr + addr); 535 + } 536 + 537 + static inline __maybe_unused void 538 + rkcif_mipi_stream_write(struct rkcif_stream *stream, unsigned int index, 539 + u32 val) 540 + { 541 + unsigned int addr = rkcif_mipi_id_get_reg(stream, index); 542 + 543 + if (addr == RKCIF_REGISTER_NOTSUPPORTED) 544 + return; 545 + 546 + writel(val, stream->rkcif->base_addr + addr); 547 + } 548 + 549 + static inline __maybe_unused u32 550 + rkcif_mipi_read(struct rkcif_interface *interface, unsigned int index) 551 + { 552 + unsigned int addr = rkcif_mipi_get_reg(interface, index); 553 + 554 + if (addr == RKCIF_REGISTER_NOTSUPPORTED) 555 + return 0; 556 + 557 + return readl(interface->rkcif->base_addr + addr); 558 + } 559 + 560 + static inline __maybe_unused u32 561 + rkcif_mipi_stream_read(struct rkcif_stream *stream, unsigned int index) 562 + { 563 + unsigned int addr = rkcif_mipi_id_get_reg(stream, index); 564 + 565 + if (addr == RKCIF_REGISTER_NOTSUPPORTED) 566 + return 0; 567 + 568 + return readl(stream->rkcif->base_addr + addr); 569 + } 570 + 571 + static void rkcif_mipi_queue_buffer(struct rkcif_stream *stream, 572 + unsigned int index) 573 + { 574 + struct rkcif_buffer *buffer = stream->buffers[index]; 575 + u32 frm_addr_y, frm_addr_uv; 576 + 577 + frm_addr_y = index ? RKCIF_MIPI_FRAME1_ADDR_Y : 578 + RKCIF_MIPI_FRAME0_ADDR_Y; 579 + frm_addr_uv = index ? RKCIF_MIPI_FRAME1_ADDR_UV : 580 + RKCIF_MIPI_FRAME0_ADDR_UV; 581 + 582 + rkcif_mipi_stream_write(stream, frm_addr_y, 583 + buffer->buff_addr[RKCIF_PLANE_Y]); 584 + rkcif_mipi_stream_write(stream, frm_addr_uv, 585 + buffer->buff_addr[RKCIF_PLANE_UV]); 586 + } 587 + 588 + static int rkcif_mipi_start_streaming(struct rkcif_stream *stream) 589 + { 590 + struct rkcif_interface *interface = stream->interface; 591 + const struct rkcif_output_fmt *active_out_fmt; 592 + const struct rkcif_mipi_match_data *match_data; 593 + struct v4l2_subdev_state *state; 594 + u32 ctrl0 = 0, ctrl1 = 0, int_temp = 0, int_mask = 0, vlw = 0; 595 + u16 height, width; 596 + int ret = -EINVAL; 597 + 598 + state = v4l2_subdev_lock_and_get_active_state(&interface->sd); 599 + 600 + active_out_fmt = rkcif_stream_find_output_fmt(stream, false, 601 + stream->pix.pixelformat); 602 + if (!active_out_fmt) 603 + goto out; 604 + 605 + height = stream->pix.height; 606 + width = stream->pix.width; 607 + vlw = stream->pix.plane_fmt[0].bytesperline; 608 + 609 + match_data = stream->rkcif->match_data->mipi; 610 + if (match_data->mipi_ctrl0) 611 + ctrl0 = match_data->mipi_ctrl0(stream, active_out_fmt); 612 + 613 + ctrl1 = RKCIF_XY_COORD(width, height); 614 + 615 + int_mask |= RKCIF_MIPI_INT_FRAME0_END(stream->id); 616 + int_mask |= RKCIF_MIPI_INT_FRAME1_END(stream->id); 617 + 618 + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTEN); 619 + int_temp |= int_mask; 620 + rkcif_mipi_write(interface, RKCIF_MIPI_INTEN, int_temp); 621 + 622 + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); 623 + int_temp &= ~int_mask; 624 + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, int_temp); 625 + 626 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME0_VLW_Y, vlw); 627 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME1_VLW_Y, vlw); 628 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME0_VLW_UV, vlw); 629 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME1_VLW_UV, vlw); 630 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CROP_START, 0x0); 631 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL1, ctrl1); 632 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL0, ctrl0); 633 + 634 + ret = 0; 635 + 636 + out: 637 + v4l2_subdev_unlock_state(state); 638 + return ret; 639 + } 640 + 641 + static void rkcif_mipi_stop_streaming(struct rkcif_stream *stream) 642 + { 643 + struct rkcif_interface *interface = stream->interface; 644 + struct v4l2_subdev_state *state; 645 + u32 int_temp = 0, int_mask = 0; 646 + 647 + state = v4l2_subdev_lock_and_get_active_state(&interface->sd); 648 + 649 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL0, 0); 650 + 651 + int_mask |= RKCIF_MIPI_INT_FRAME0_END(stream->id); 652 + int_mask |= RKCIF_MIPI_INT_FRAME1_END(stream->id); 653 + 654 + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTEN); 655 + int_temp &= ~int_mask; 656 + rkcif_mipi_write(interface, RKCIF_MIPI_INTEN, int_temp); 657 + 658 + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); 659 + int_temp &= ~int_mask; 660 + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, int_temp); 661 + 662 + stream->stopping = false; 663 + 664 + v4l2_subdev_unlock_state(state); 665 + } 666 + 667 + static void rkcif_mipi_set_crop(struct rkcif_stream *stream, u16 left, u16 top) 668 + { 669 + u32 val; 670 + 671 + val = RKCIF_XY_COORD(left, top); 672 + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CROP_START, val); 673 + } 674 + 675 + irqreturn_t rkcif_mipi_isr(int irq, void *ctx) 676 + { 677 + struct device *dev = ctx; 678 + struct rkcif_device *rkcif = dev_get_drvdata(dev); 679 + irqreturn_t ret = IRQ_NONE; 680 + u32 intstat; 681 + 682 + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { 683 + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; 684 + struct rkcif_interface *interface = &rkcif->interfaces[index]; 685 + 686 + intstat = rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); 687 + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, intstat); 688 + 689 + for (unsigned int j = 0; j < interface->streams_num; j++) { 690 + struct rkcif_stream *stream = &interface->streams[j]; 691 + 692 + if (intstat & RKCIF_MIPI_INT_FRAME0_END(stream->id) || 693 + intstat & RKCIF_MIPI_INT_FRAME1_END(stream->id)) { 694 + ret = IRQ_HANDLED; 695 + 696 + if (stream->stopping) { 697 + rkcif_mipi_stop_streaming(stream); 698 + wake_up(&stream->wq_stopped); 699 + continue; 700 + } 701 + 702 + rkcif_stream_pingpong(stream); 703 + } 704 + } 705 + } 706 + 707 + return ret; 708 + } 709 + 710 + int rkcif_mipi_register(struct rkcif_device *rkcif) 711 + { 712 + int ret; 713 + 714 + if (!rkcif->match_data->mipi) 715 + return 0; 716 + 717 + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { 718 + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; 719 + struct rkcif_interface *interface = &rkcif->interfaces[index]; 720 + 721 + interface->index = index; 722 + interface->type = RKCIF_IF_MIPI; 723 + interface->in_fmts = mipi_in_fmts; 724 + interface->in_fmts_num = ARRAY_SIZE(mipi_in_fmts); 725 + interface->set_crop = rkcif_mipi_set_crop; 726 + interface->streams_num = 0; 727 + ret = rkcif_interface_register(rkcif, interface); 728 + if (ret) 729 + continue; 730 + 731 + for (unsigned int j = 0; j < RKCIF_ID_MAX; j++) { 732 + struct rkcif_stream *stream = &interface->streams[j]; 733 + 734 + stream->id = j; 735 + stream->interface = interface; 736 + stream->out_fmts = mipi_out_fmts; 737 + stream->out_fmts_num = ARRAY_SIZE(mipi_out_fmts); 738 + stream->queue_buffer = rkcif_mipi_queue_buffer; 739 + stream->start_streaming = rkcif_mipi_start_streaming; 740 + stream->stop_streaming = rkcif_mipi_stop_streaming; 741 + ret = rkcif_stream_register(rkcif, stream); 742 + if (ret) 743 + goto err; 744 + interface->streams_num++; 745 + } 746 + } 747 + 748 + return 0; 749 + 750 + err: 751 + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { 752 + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; 753 + struct rkcif_interface *interface = &rkcif->interfaces[index]; 754 + 755 + for (unsigned int j = 0; j < interface->streams_num; j++) 756 + rkcif_stream_unregister(&interface->streams[j]); 757 + 758 + rkcif_interface_unregister(interface); 759 + } 760 + return ret; 761 + } 762 + 763 + void rkcif_mipi_unregister(struct rkcif_device *rkcif) 764 + { 765 + if (!rkcif->match_data->mipi) 766 + return; 767 + 768 + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { 769 + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; 770 + struct rkcif_interface *interface = &rkcif->interfaces[index]; 771 + 772 + for (unsigned int j = 0; j < interface->streams_num; j++) 773 + rkcif_stream_unregister(&interface->streams[j]); 774 + 775 + rkcif_interface_unregister(interface); 776 + } 777 + }
+23
drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Rockchip Camera Interface (CIF) Driver 4 + * 5 + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. 6 + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> 7 + * Copyright (C) 2025 Collabora, Ltd. 8 + */ 9 + 10 + #ifndef _RKCIF_CAPTURE_MIPI_H 11 + #define _RKCIF_CAPTURE_MIPI_H 12 + 13 + #include "rkcif-common.h" 14 + 15 + extern const struct rkcif_mipi_match_data rkcif_rk3568_vicap_mipi_match_data; 16 + 17 + int rkcif_mipi_register(struct rkcif_device *rkcif); 18 + 19 + void rkcif_mipi_unregister(struct rkcif_device *rkcif); 20 + 21 + irqreturn_t rkcif_mipi_isr(int irq, void *ctx); 22 + 23 + #endif
+29
drivers/media/platform/rockchip/rkcif/rkcif-common.h
··· 73 73 RKCIF_IF_MIPI, 74 74 }; 75 75 76 + enum rkcif_mipi_format_type { 77 + RKCIF_MIPI_TYPE_INVALID, 78 + RKCIF_MIPI_TYPE_RAW8, 79 + RKCIF_MIPI_TYPE_RAW10, 80 + RKCIF_MIPI_TYPE_RAW12, 81 + RKCIF_MIPI_TYPE_RGB888, 82 + RKCIF_MIPI_TYPE_YUV422SP, 83 + RKCIF_MIPI_TYPE_YUV420SP, 84 + RKCIF_MIPI_TYPE_YUV400, 85 + }; 86 + 76 87 struct rkcif_buffer { 77 88 struct vb2_v4l2_buffer vb; 78 89 struct list_head queue; ··· 118 107 u32 fourcc; 119 108 u32 mbus_code; 120 109 u8 cplanes; 110 + u8 depth; 121 111 122 112 union { 123 113 u32 dvp_fmt_val; 114 + struct { 115 + u8 dt; 116 + bool compact; 117 + enum rkcif_mipi_format_type type; 118 + } mipi; 124 119 }; 125 120 }; 126 121 ··· 201 184 void (*set_crop)(struct rkcif_stream *stream, u16 left, u16 top); 202 185 }; 203 186 187 + struct rkcif_mipi_match_data { 188 + unsigned int mipi_num; 189 + unsigned int regs[RKCIF_MIPI_REGISTER_MAX]; 190 + unsigned int regs_id[RKCIF_ID_MAX][RKCIF_MIPI_ID_REGISTER_MAX]; 191 + u32 (*mipi_ctrl0)(struct rkcif_stream *stream, 192 + const struct rkcif_output_fmt *active_out_fmt); 193 + struct { 194 + unsigned int offset; 195 + } blocks[RKCIF_MIPI_MAX - RKCIF_MIPI_BASE]; 196 + }; 197 + 204 198 struct rkcif_dvp_match_data { 205 199 const struct rkcif_input_fmt *in_fmts; 206 200 unsigned int in_fmts_num; ··· 227 199 const char *const *clks; 228 200 unsigned int clks_num; 229 201 const struct rkcif_dvp_match_data *dvp; 202 + const struct rkcif_mipi_match_data *mipi; 230 203 }; 231 204 232 205 struct rkcif_device {
+12
drivers/media/platform/rockchip/rkcif/rkcif-dev.c
··· 24 24 #include <media/v4l2-mc.h> 25 25 26 26 #include "rkcif-capture-dvp.h" 27 + #include "rkcif-capture-mipi.h" 27 28 #include "rkcif-common.h" 28 29 29 30 static const char *const px30_vip_clks[] = { ··· 50 49 .clks = rk3568_vicap_clks, 51 50 .clks_num = ARRAY_SIZE(rk3568_vicap_clks), 52 51 .dvp = &rkcif_rk3568_vicap_dvp_match_data, 52 + .mipi = &rkcif_rk3568_vicap_mipi_match_data, 53 53 }; 54 54 55 55 static const struct of_device_id rkcif_plat_of_match[] = { ··· 74 72 if (ret && ret != -ENODEV) 75 73 goto err; 76 74 75 + ret = rkcif_mipi_register(rkcif); 76 + if (ret && ret != -ENODEV) 77 + goto err_dvp_unregister; 78 + 77 79 return 0; 78 80 81 + err_dvp_unregister: 82 + rkcif_dvp_unregister(rkcif); 79 83 err: 80 84 return ret; 81 85 } 82 86 83 87 static void rkcif_unregister(struct rkcif_device *rkcif) 84 88 { 89 + rkcif_mipi_unregister(rkcif); 85 90 rkcif_dvp_unregister(rkcif); 86 91 } 87 92 ··· 135 126 irqreturn_t ret = IRQ_NONE; 136 127 137 128 if (rkcif_dvp_isr(irq, ctx) == IRQ_HANDLED) 129 + ret = IRQ_HANDLED; 130 + 131 + if (rkcif_mipi_isr(irq, ctx) == IRQ_HANDLED) 138 132 ret = IRQ_HANDLED; 139 133 140 134 return ret;
+22
drivers/media/platform/rockchip/rkcif/rkcif-regs.h
··· 128 128 RKCIF_DVP_REGISTER_MAX 129 129 }; 130 130 131 + enum rkcif_mipi_register_index { 132 + RKCIF_MIPI_CTRL, 133 + RKCIF_MIPI_INTEN, 134 + RKCIF_MIPI_INTSTAT, 135 + RKCIF_MIPI_REGISTER_MAX 136 + }; 137 + 138 + enum rkcif_mipi_id_register_index { 139 + RKCIF_MIPI_CTRL0, 140 + RKCIF_MIPI_CTRL1, 141 + RKCIF_MIPI_FRAME0_ADDR_Y, 142 + RKCIF_MIPI_FRAME0_ADDR_UV, 143 + RKCIF_MIPI_FRAME0_VLW_Y, 144 + RKCIF_MIPI_FRAME0_VLW_UV, 145 + RKCIF_MIPI_FRAME1_ADDR_Y, 146 + RKCIF_MIPI_FRAME1_ADDR_UV, 147 + RKCIF_MIPI_FRAME1_VLW_Y, 148 + RKCIF_MIPI_FRAME1_VLW_UV, 149 + RKCIF_MIPI_CROP_START, 150 + RKCIF_MIPI_ID_REGISTER_MAX 151 + }; 152 + 131 153 #endif