1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2013 - 2025 Intel Corporation 4 */ 5 6 #include <linux/atomic.h> 7 #include <linux/bits.h> 8 #include <linux/bug.h> 9 #include <linux/delay.h> 10 #include <linux/device.h> 11 #include <linux/io.h> 12 #include <linux/minmax.h> 13 #include <linux/mutex.h> 14 #include <linux/slab.h> 15 16 #include <media/media-entity.h> 17 #include <media/v4l2-ctrls.h> 18 #include <media/v4l2-device.h> 19 #include <media/v4l2-event.h> 20 #include <media/v4l2-subdev.h> 21 22 #include "ipu7.h" 23 #include "ipu7-bus.h" 24 #include "ipu7-isys.h" 25 #include "ipu7-isys-csi2.h" 26 #include "ipu7-isys-csi2-regs.h" 27 #include "ipu7-isys-csi-phy.h" 28 29 static const u32 csi2_supported_codes[] = { 30 MEDIA_BUS_FMT_Y10_1X10, 31 MEDIA_BUS_FMT_RGB565_1X16, 32 MEDIA_BUS_FMT_RGB888_1X24, 33 MEDIA_BUS_FMT_UYVY8_1X16, 34 MEDIA_BUS_FMT_YUYV8_1X16, 35 MEDIA_BUS_FMT_YUYV10_1X20, 36 MEDIA_BUS_FMT_SBGGR10_1X10, 37 MEDIA_BUS_FMT_SGBRG10_1X10, 38 MEDIA_BUS_FMT_SGRBG10_1X10, 39 MEDIA_BUS_FMT_SRGGB10_1X10, 40 MEDIA_BUS_FMT_SBGGR12_1X12, 41 MEDIA_BUS_FMT_SGBRG12_1X12, 42 MEDIA_BUS_FMT_SGRBG12_1X12, 43 MEDIA_BUS_FMT_SRGGB12_1X12, 44 MEDIA_BUS_FMT_SBGGR8_1X8, 45 MEDIA_BUS_FMT_SGBRG8_1X8, 46 MEDIA_BUS_FMT_SGRBG8_1X8, 47 MEDIA_BUS_FMT_SRGGB8_1X8, 48 0, 49 }; 50 51 s64 ipu7_isys_csi2_get_link_freq(struct ipu7_isys_csi2 *csi2) 52 { 53 struct media_pad *src_pad; 54 55 src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity); 56 if (IS_ERR(src_pad)) { 57 dev_err(&csi2->isys->adev->auxdev.dev, 58 "can't get source pad of %s (%ld)\n", 59 csi2->asd.sd.name, PTR_ERR(src_pad)); 60 return PTR_ERR(src_pad); 61 } 62 63 return v4l2_get_link_freq(src_pad, 0, 0); 64 } 65 66 static int csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, 67 struct v4l2_event_subscription *sub) 68 { 69 struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); 70 struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd); 71 struct device *dev = &csi2->isys->adev->auxdev.dev; 72 73 dev_dbg(dev, "csi2 subscribe event(type %u id %u)\n", 74 sub->type, sub->id); 75 76 switch (sub->type) { 77 case V4L2_EVENT_FRAME_SYNC: 78 return v4l2_event_subscribe(fh, sub, 10, NULL); 79 case V4L2_EVENT_CTRL: 80 return v4l2_ctrl_subscribe_event(fh, sub); 81 default: 82 return -EINVAL; 83 } 84 } 85 86 static const struct v4l2_subdev_core_ops csi2_sd_core_ops = { 87 .subscribe_event = csi2_subscribe_event, 88 .unsubscribe_event = v4l2_event_subdev_unsubscribe, 89 }; 90 91 static void csi2_irq_enable(struct ipu7_isys_csi2 *csi2) 92 { 93 struct ipu7_device *isp = csi2->isys->adev->isp; 94 unsigned int offset, mask; 95 96 /* enable CSI2 legacy error irq */ 97 offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port); 98 mask = IPU7_CSI_RX_ERROR_IRQ_MASK; 99 writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); 100 writel(mask, csi2->base + offset + IRQ_CTL_MASK); 101 writel(mask, csi2->base + offset + IRQ_CTL_ENABLE); 102 103 /* enable CSI2 legacy sync irq */ 104 offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port); 105 mask = IPU7_CSI_RX_SYNC_IRQ_MASK; 106 writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); 107 writel(mask, csi2->base + offset + IRQ_CTL_MASK); 108 writel(mask, csi2->base + offset + IRQ_CTL_ENABLE); 109 110 mask = IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK; 111 if (!is_ipu7(isp->hw_ver)) { 112 writel(mask, csi2->base + offset + IRQ1_CTL_CLEAR); 113 writel(mask, csi2->base + offset + IRQ1_CTL_MASK); 114 writel(mask, csi2->base + offset + IRQ1_CTL_ENABLE); 115 } 116 } 117 118 static void csi2_irq_disable(struct ipu7_isys_csi2 *csi2) 119 { 120 struct ipu7_device *isp = csi2->isys->adev->isp; 121 unsigned int offset, mask; 122 123 /* disable CSI2 legacy error irq */ 124 offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port); 125 mask = IPU7_CSI_RX_ERROR_IRQ_MASK; 126 writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); 127 writel(0, csi2->base + offset + IRQ_CTL_MASK); 128 writel(0, csi2->base + offset + IRQ_CTL_ENABLE); 129 130 /* disable CSI2 legacy sync irq */ 131 offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port); 132 mask = IPU7_CSI_RX_SYNC_IRQ_MASK; 133 writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); 134 writel(0, csi2->base + offset + IRQ_CTL_MASK); 135 writel(0, csi2->base + offset + IRQ_CTL_ENABLE); 136 137 if (!is_ipu7(isp->hw_ver)) { 138 writel(mask, csi2->base + offset + IRQ1_CTL_CLEAR); 139 writel(0, csi2->base + offset + IRQ1_CTL_MASK); 140 writel(0, csi2->base + offset + IRQ1_CTL_ENABLE); 141 } 142 } 143 144 static void ipu7_isys_csi2_disable_stream(struct ipu7_isys_csi2 *csi2) 145 { 146 struct ipu7_isys *isys = csi2->isys; 147 void __iomem *isys_base = isys->pdata->base; 148 149 ipu7_isys_csi_phy_powerdown(csi2); 150 151 writel(0x4, isys_base + IS_IO_GPREGS_BASE + CLK_DIV_FACTOR_APB_CLK); 152 csi2_irq_disable(csi2); 153 } 154 155 static int ipu7_isys_csi2_enable_stream(struct ipu7_isys_csi2 *csi2) 156 { 157 struct ipu7_isys *isys = csi2->isys; 158 struct device *dev = &isys->adev->auxdev.dev; 159 void __iomem *isys_base = isys->pdata->base; 160 unsigned int port, nlanes, offset; 161 int ret; 162 163 port = csi2->port; 164 nlanes = csi2->nlanes; 165 166 offset = IS_IO_GPREGS_BASE; 167 writel(0x2, isys_base + offset + CLK_DIV_FACTOR_APB_CLK); 168 dev_dbg(dev, "port %u CLK_GATE = 0x%04x DIV_FACTOR_APB_CLK=0x%04x\n", 169 port, readl(isys_base + offset + CSI_PORT_CLK_GATE), 170 readl(isys_base + offset + CLK_DIV_FACTOR_APB_CLK)); 171 if (port == 0U && nlanes == 4U && !is_ipu7(isys->adev->isp->hw_ver)) { 172 dev_dbg(dev, "CSI port %u in aggregation mode\n", port); 173 writel(0x1, isys_base + offset + CSI_PORTAB_AGGREGATION); 174 } 175 176 /* input is coming from CSI receiver (sensor) */ 177 offset = IS_IO_CSI2_ADPL_PORT_BASE(port); 178 writel(CSI_SENSOR_INPUT, isys_base + offset + CSI2_ADPL_INPUT_MODE); 179 writel(1, isys_base + offset + CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN); 180 181 ret = ipu7_isys_csi_phy_powerup(csi2); 182 if (ret) { 183 dev_err(dev, "CSI-%d PHY power up failed %d\n", port, ret); 184 return ret; 185 } 186 187 csi2_irq_enable(csi2); 188 189 return 0; 190 } 191 192 static int ipu7_isys_csi2_set_sel(struct v4l2_subdev *sd, 193 struct v4l2_subdev_state *state, 194 struct v4l2_subdev_selection *sel) 195 { 196 struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); 197 struct device *dev = &asd->isys->adev->auxdev.dev; 198 struct v4l2_mbus_framefmt *sink_ffmt; 199 struct v4l2_mbus_framefmt *src_ffmt; 200 struct v4l2_rect *crop; 201 202 if (sel->pad == IPU7_CSI2_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) 203 return -EINVAL; 204 205 sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state, 206 sel->pad, 207 sel->stream); 208 if (!sink_ffmt) 209 return -EINVAL; 210 211 src_ffmt = v4l2_subdev_state_get_format(state, sel->pad, sel->stream); 212 if (!src_ffmt) 213 return -EINVAL; 214 215 crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); 216 if (!crop) 217 return -EINVAL; 218 219 /* Only vertical cropping is supported */ 220 sel->r.left = 0; 221 sel->r.width = sink_ffmt->width; 222 /* Non-bayer formats can't be single line cropped */ 223 if (!ipu7_isys_is_bayer_format(sink_ffmt->code)) 224 sel->r.top &= ~1U; 225 sel->r.height = clamp(sel->r.height & ~1U, IPU_ISYS_MIN_HEIGHT, 226 sink_ffmt->height - sel->r.top); 227 *crop = sel->r; 228 229 /* update source pad format */ 230 src_ffmt->width = sel->r.width; 231 src_ffmt->height = sel->r.height; 232 if (ipu7_isys_is_bayer_format(sink_ffmt->code)) 233 src_ffmt->code = ipu7_isys_convert_bayer_order(sink_ffmt->code, 234 sel->r.left, 235 sel->r.top); 236 dev_dbg(dev, "set crop for %s sel: %d,%d,%d,%d code: 0x%x\n", 237 sd->name, sel->r.left, sel->r.top, sel->r.width, sel->r.height, 238 src_ffmt->code); 239 240 return 0; 241 } 242 243 static int ipu7_isys_csi2_get_sel(struct v4l2_subdev *sd, 244 struct v4l2_subdev_state *state, 245 struct v4l2_subdev_selection *sel) 246 { 247 struct v4l2_mbus_framefmt *sink_ffmt; 248 struct v4l2_rect *crop; 249 int ret = 0; 250 251 if (sd->entity.pads[sel->pad].flags & MEDIA_PAD_FL_SINK) 252 return -EINVAL; 253 254 sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state, 255 sel->pad, 256 sel->stream); 257 if (!sink_ffmt) 258 return -EINVAL; 259 260 crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); 261 if (!crop) 262 return -EINVAL; 263 264 switch (sel->target) { 265 case V4L2_SEL_TGT_CROP_DEFAULT: 266 case V4L2_SEL_TGT_CROP_BOUNDS: 267 sel->r.left = 0; 268 sel->r.top = 0; 269 sel->r.width = sink_ffmt->width; 270 sel->r.height = sink_ffmt->height; 271 break; 272 case V4L2_SEL_TGT_CROP: 273 sel->r = *crop; 274 break; 275 default: 276 ret = -EINVAL; 277 } 278 279 return ret; 280 } 281 282 /* 283 * Maximum stream ID is 63 for now, as we use u64 bitmask to represent a set 284 * of streams. 285 */ 286 #define CSI2_SUBDEV_MAX_STREAM_ID 63 287 288 static int ipu7_isys_csi2_enable_streams(struct v4l2_subdev *sd, 289 struct v4l2_subdev_state *state, 290 u32 pad, u64 streams_mask) 291 { 292 struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); 293 struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd); 294 struct v4l2_subdev *r_sd; 295 struct media_pad *rp; 296 u32 sink_pad, sink_stream; 297 int ret, i; 298 299 if (!csi2->stream_count) { 300 dev_dbg(&csi2->isys->adev->auxdev.dev, 301 "stream on CSI2-%u with %u lanes\n", csi2->port, 302 csi2->nlanes); 303 ret = ipu7_isys_csi2_enable_stream(csi2); 304 if (ret) 305 return ret; 306 } 307 308 for (i = 0; i <= CSI2_SUBDEV_MAX_STREAM_ID; i++) { 309 if (streams_mask & BIT_ULL(i)) 310 break; 311 } 312 313 ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, i, 314 &sink_pad, &sink_stream); 315 if (ret) 316 return ret; 317 318 rp = media_pad_remote_pad_first(&sd->entity.pads[IPU7_CSI2_PAD_SINK]); 319 r_sd = media_entity_to_v4l2_subdev(rp->entity); 320 321 ret = v4l2_subdev_enable_streams(r_sd, rp->index, 322 BIT_ULL(sink_stream)); 323 if (!ret) { 324 csi2->stream_count++; 325 return 0; 326 } 327 328 if (!csi2->stream_count) 329 ipu7_isys_csi2_disable_stream(csi2); 330 331 return ret; 332 } 333 334 static int ipu7_isys_csi2_disable_streams(struct v4l2_subdev *sd, 335 struct v4l2_subdev_state *state, 336 u32 pad, u64 streams_mask) 337 { 338 struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); 339 struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd); 340 struct v4l2_subdev *r_sd; 341 struct media_pad *rp; 342 u32 sink_pad, sink_stream; 343 int ret, i; 344 345 for (i = 0; i <= CSI2_SUBDEV_MAX_STREAM_ID; i++) { 346 if (streams_mask & BIT_ULL(i)) 347 break; 348 } 349 350 ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, i, 351 &sink_pad, &sink_stream); 352 if (ret) 353 return ret; 354 355 rp = media_pad_remote_pad_first(&sd->entity.pads[IPU7_CSI2_PAD_SINK]); 356 r_sd = media_entity_to_v4l2_subdev(rp->entity); 357 358 v4l2_subdev_disable_streams(r_sd, rp->index, BIT_ULL(sink_stream)); 359 360 if (--csi2->stream_count) 361 return 0; 362 363 dev_dbg(&csi2->isys->adev->auxdev.dev, 364 "stream off CSI2-%u with %u lanes\n", csi2->port, csi2->nlanes); 365 366 ipu7_isys_csi2_disable_stream(csi2); 367 368 return 0; 369 } 370 371 static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = { 372 .get_fmt = v4l2_subdev_get_fmt, 373 .set_fmt = ipu7_isys_subdev_set_fmt, 374 .get_selection = ipu7_isys_csi2_get_sel, 375 .set_selection = ipu7_isys_csi2_set_sel, 376 .enum_mbus_code = ipu7_isys_subdev_enum_mbus_code, 377 .enable_streams = ipu7_isys_csi2_enable_streams, 378 .disable_streams = ipu7_isys_csi2_disable_streams, 379 .set_routing = ipu7_isys_subdev_set_routing, 380 }; 381 382 static const struct v4l2_subdev_ops csi2_sd_ops = { 383 .core = &csi2_sd_core_ops, 384 .pad = &csi2_sd_pad_ops, 385 }; 386 387 static const struct media_entity_operations csi2_entity_ops = { 388 .link_validate = v4l2_subdev_link_validate, 389 .has_pad_interdep = v4l2_subdev_has_pad_interdep, 390 }; 391 392 void ipu7_isys_csi2_cleanup(struct ipu7_isys_csi2 *csi2) 393 { 394 if (!csi2->isys) 395 return; 396 397 v4l2_device_unregister_subdev(&csi2->asd.sd); 398 v4l2_subdev_cleanup(&csi2->asd.sd); 399 ipu7_isys_subdev_cleanup(&csi2->asd); 400 csi2->isys = NULL; 401 } 402 403 int ipu7_isys_csi2_init(struct ipu7_isys_csi2 *csi2, 404 struct ipu7_isys *isys, 405 void __iomem *base, unsigned int index) 406 { 407 struct device *dev = &isys->adev->auxdev.dev; 408 int ret; 409 410 csi2->isys = isys; 411 csi2->base = base; 412 csi2->port = index; 413 414 if (!is_ipu7(isys->adev->isp->hw_ver)) 415 csi2->legacy_irq_mask = 0x7U << (index * 3U); 416 else 417 csi2->legacy_irq_mask = 0x3U << (index * 2U); 418 419 dev_dbg(dev, "csi-%d legacy irq mask = 0x%x\n", index, 420 csi2->legacy_irq_mask); 421 422 csi2->asd.sd.entity.ops = &csi2_entity_ops; 423 csi2->asd.isys = isys; 424 425 ret = ipu7_isys_subdev_init(&csi2->asd, &csi2_sd_ops, 0, 426 IPU7_NR_OF_CSI2_SINK_PADS, 427 IPU7_NR_OF_CSI2_SRC_PADS); 428 if (ret) 429 return ret; 430 431 csi2->asd.source = (int)index; 432 csi2->asd.supported_codes = csi2_supported_codes; 433 snprintf(csi2->asd.sd.name, sizeof(csi2->asd.sd.name), 434 IPU_ISYS_ENTITY_PREFIX " CSI2 %u", index); 435 v4l2_set_subdevdata(&csi2->asd.sd, &csi2->asd); 436 437 ret = v4l2_subdev_init_finalize(&csi2->asd.sd); 438 if (ret) { 439 dev_err(dev, "failed to init v4l2 subdev (%d)\n", ret); 440 goto isys_subdev_cleanup; 441 } 442 443 ret = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2->asd.sd); 444 if (ret) { 445 dev_err(dev, "failed to register v4l2 subdev (%d)\n", ret); 446 goto v4l2_subdev_cleanup; 447 } 448 449 return 0; 450 451 v4l2_subdev_cleanup: 452 v4l2_subdev_cleanup(&csi2->asd.sd); 453 isys_subdev_cleanup: 454 ipu7_isys_subdev_cleanup(&csi2->asd); 455 456 return ret; 457 } 458 459 void ipu7_isys_csi2_sof_event_by_stream(struct ipu7_isys_stream *stream) 460 { 461 struct ipu7_isys_csi2 *csi2 = ipu7_isys_subdev_to_csi2(stream->asd); 462 struct device *dev = &stream->isys->adev->auxdev.dev; 463 struct video_device *vdev = csi2->asd.sd.devnode; 464 struct v4l2_event ev = { 465 .type = V4L2_EVENT_FRAME_SYNC, 466 }; 467 468 ev.id = stream->vc; 469 ev.u.frame_sync.frame_sequence = atomic_fetch_inc(&stream->sequence); 470 v4l2_event_queue(vdev, &ev); 471 472 dev_dbg(dev, "sof_event::csi2-%i sequence: %i, vc: %d\n", 473 csi2->port, ev.u.frame_sync.frame_sequence, stream->vc); 474 } 475 476 void ipu7_isys_csi2_eof_event_by_stream(struct ipu7_isys_stream *stream) 477 { 478 struct ipu7_isys_csi2 *csi2 = ipu7_isys_subdev_to_csi2(stream->asd); 479 struct device *dev = &stream->isys->adev->auxdev.dev; 480 u32 frame_sequence = atomic_read(&stream->sequence); 481 482 dev_dbg(dev, "eof_event::csi2-%i sequence: %i\n", 483 csi2->port, frame_sequence); 484 } 485 486 int ipu7_isys_csi2_get_remote_desc(u32 source_stream, 487 struct ipu7_isys_csi2 *csi2, 488 struct media_entity *source_entity, 489 struct v4l2_mbus_frame_desc_entry *entry, 490 int *nr_queues) 491 { 492 struct v4l2_mbus_frame_desc_entry *desc_entry = NULL; 493 struct device *dev = &csi2->isys->adev->auxdev.dev; 494 struct v4l2_mbus_frame_desc desc; 495 struct v4l2_subdev *source; 496 struct media_pad *pad; 497 unsigned int i; 498 int ret; 499 500 source = media_entity_to_v4l2_subdev(source_entity); 501 if (!source) 502 return -EPIPE; 503 504 pad = media_pad_remote_pad_first(&csi2->asd.pad[IPU7_CSI2_PAD_SINK]); 505 if (!pad) 506 return -EPIPE; 507 508 ret = v4l2_subdev_call(source, pad, get_frame_desc, pad->index, &desc); 509 if (ret) 510 return ret; 511 512 if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { 513 dev_err(dev, "Unsupported frame descriptor type\n"); 514 return -EINVAL; 515 } 516 517 for (i = 0; i < desc.num_entries; i++) { 518 if (source_stream == desc.entry[i].stream) { 519 desc_entry = &desc.entry[i]; 520 break; 521 } 522 } 523 524 if (!desc_entry) { 525 dev_err(dev, "Failed to find stream %u from remote subdev\n", 526 source_stream); 527 return -EINVAL; 528 } 529 530 if (desc_entry->bus.csi2.vc >= IPU7_NR_OF_CSI2_VC) { 531 dev_err(dev, "invalid vc %d\n", desc_entry->bus.csi2.vc); 532 return -EINVAL; 533 } 534 535 *entry = *desc_entry; 536 537 for (i = 0; i < desc.num_entries; i++) { 538 if (desc_entry->bus.csi2.vc == desc.entry[i].bus.csi2.vc) 539 (*nr_queues)++; 540 } 541 542 return 0; 543 } 544