1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * vsp1_drv.c -- R-Car VSP1 Driver 4 * 5 * Copyright (C) 2013-2015 Renesas Electronics Corporation 6 * 7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 8 */ 9 10 #include <linux/clk.h> 11 #include <linux/delay.h> 12 #include <linux/device.h> 13 #include <linux/interrupt.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/of_device.h> 17 #include <linux/platform_device.h> 18 #include <linux/pm_runtime.h> 19 #include <linux/reset.h> 20 #include <linux/videodev2.h> 21 22 #include <media/rcar-fcp.h> 23 #include <media/v4l2-subdev.h> 24 25 #include "vsp1.h" 26 #include "vsp1_brx.h" 27 #include "vsp1_clu.h" 28 #include "vsp1_dl.h" 29 #include "vsp1_drm.h" 30 #include "vsp1_hgo.h" 31 #include "vsp1_hgt.h" 32 #include "vsp1_hsit.h" 33 #include "vsp1_lif.h" 34 #include "vsp1_lut.h" 35 #include "vsp1_pipe.h" 36 #include "vsp1_rwpf.h" 37 #include "vsp1_sru.h" 38 #include "vsp1_uds.h" 39 #include "vsp1_uif.h" 40 #include "vsp1_video.h" 41 42 /* ----------------------------------------------------------------------------- 43 * Interrupt Handling 44 */ 45 46 static irqreturn_t vsp1_irq_handler(int irq, void *data) 47 { 48 u32 mask = VI6_WPF_IRQ_STA_DFE | VI6_WPF_IRQ_STA_FRE | 49 VI6_WPF_IRQ_STA_UND; 50 struct vsp1_device *vsp1 = data; 51 irqreturn_t ret = IRQ_NONE; 52 unsigned int i; 53 u32 status; 54 55 for (i = 0; i < vsp1->info->wpf_count; ++i) { 56 struct vsp1_rwpf *wpf = vsp1->wpf[i]; 57 58 if (wpf == NULL) 59 continue; 60 61 status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); 62 vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); 63 64 if ((status & VI6_WPF_IRQ_STA_UND) && wpf->entity.pipe) { 65 wpf->entity.pipe->underrun_count++; 66 67 dev_warn_ratelimited(vsp1->dev, 68 "Underrun occurred at WPF%u (total underruns %u)\n", 69 i, wpf->entity.pipe->underrun_count); 70 } 71 72 if (status & VI6_WPF_IRQ_STA_DFE) { 73 vsp1_pipeline_frame_end(wpf->entity.pipe); 74 ret = IRQ_HANDLED; 75 } 76 } 77 78 return ret; 79 } 80 81 /* ----------------------------------------------------------------------------- 82 * Entities 83 */ 84 85 /* 86 * vsp1_create_sink_links - Create links from all sources to the given sink 87 * 88 * This function creates media links from all valid sources to the given sink 89 * pad. Links that would be invalid according to the VSP1 hardware capabilities 90 * are skipped. Those include all links 91 * 92 * - from a UDS to a UDS (UDS entities can't be chained) 93 * - from an entity to itself (no loops are allowed) 94 * 95 * Furthermore, the BRS can't be connected to histogram generators, but no 96 * special check is currently needed as all VSP instances that include a BRS 97 * have no histogram generator. 98 */ 99 static int vsp1_create_sink_links(struct vsp1_device *vsp1, 100 struct vsp1_entity *sink) 101 { 102 struct media_entity *entity = &sink->subdev.entity; 103 struct vsp1_entity *source; 104 unsigned int pad; 105 int ret; 106 107 list_for_each_entry(source, &vsp1->entities, list_dev) { 108 u32 flags; 109 110 if (source->type == sink->type) 111 continue; 112 113 if (source->type == VSP1_ENTITY_HGO || 114 source->type == VSP1_ENTITY_HGT || 115 source->type == VSP1_ENTITY_LIF || 116 source->type == VSP1_ENTITY_WPF) 117 continue; 118 119 flags = source->type == VSP1_ENTITY_RPF && 120 sink->type == VSP1_ENTITY_WPF && 121 source->index == sink->index 122 ? MEDIA_LNK_FL_ENABLED : 0; 123 124 for (pad = 0; pad < entity->num_pads; ++pad) { 125 if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK)) 126 continue; 127 128 ret = media_create_pad_link(&source->subdev.entity, 129 source->source_pad, 130 entity, pad, flags); 131 if (ret < 0) 132 return ret; 133 134 if (flags & MEDIA_LNK_FL_ENABLED) 135 source->sink = sink; 136 } 137 } 138 139 return 0; 140 } 141 142 static int vsp1_uapi_create_links(struct vsp1_device *vsp1) 143 { 144 struct vsp1_entity *entity; 145 unsigned int i; 146 int ret; 147 148 list_for_each_entry(entity, &vsp1->entities, list_dev) { 149 if (entity->type == VSP1_ENTITY_LIF || 150 entity->type == VSP1_ENTITY_RPF) 151 continue; 152 153 ret = vsp1_create_sink_links(vsp1, entity); 154 if (ret < 0) 155 return ret; 156 } 157 158 if (vsp1->hgo) { 159 ret = media_create_pad_link(&vsp1->hgo->histo.entity.subdev.entity, 160 HISTO_PAD_SOURCE, 161 &vsp1->hgo->histo.video.entity, 0, 162 MEDIA_LNK_FL_ENABLED | 163 MEDIA_LNK_FL_IMMUTABLE); 164 if (ret < 0) 165 return ret; 166 } 167 168 if (vsp1->hgt) { 169 ret = media_create_pad_link(&vsp1->hgt->histo.entity.subdev.entity, 170 HISTO_PAD_SOURCE, 171 &vsp1->hgt->histo.video.entity, 0, 172 MEDIA_LNK_FL_ENABLED | 173 MEDIA_LNK_FL_IMMUTABLE); 174 if (ret < 0) 175 return ret; 176 } 177 178 for (i = 0; i < vsp1->info->lif_count; ++i) { 179 if (!vsp1->lif[i]) 180 continue; 181 182 ret = media_create_pad_link(&vsp1->wpf[i]->entity.subdev.entity, 183 RWPF_PAD_SOURCE, 184 &vsp1->lif[i]->entity.subdev.entity, 185 LIF_PAD_SINK, 0); 186 if (ret < 0) 187 return ret; 188 } 189 190 for (i = 0; i < vsp1->info->rpf_count; ++i) { 191 struct vsp1_rwpf *rpf = vsp1->rpf[i]; 192 193 ret = media_create_pad_link(&rpf->video->video.entity, 0, 194 &rpf->entity.subdev.entity, 195 RWPF_PAD_SINK, 196 MEDIA_LNK_FL_ENABLED | 197 MEDIA_LNK_FL_IMMUTABLE); 198 if (ret < 0) 199 return ret; 200 } 201 202 for (i = 0; i < vsp1->info->wpf_count; ++i) { 203 /* 204 * Connect the video device to the WPF. All connections are 205 * immutable. 206 */ 207 struct vsp1_rwpf *wpf = vsp1->wpf[i]; 208 209 ret = media_create_pad_link(&wpf->entity.subdev.entity, 210 RWPF_PAD_SOURCE, 211 &wpf->video->video.entity, 0, 212 MEDIA_LNK_FL_IMMUTABLE | 213 MEDIA_LNK_FL_ENABLED); 214 if (ret < 0) 215 return ret; 216 } 217 218 return 0; 219 } 220 221 static void vsp1_destroy_entities(struct vsp1_device *vsp1) 222 { 223 struct vsp1_entity *entity, *_entity; 224 struct vsp1_video *video, *_video; 225 226 list_for_each_entry_safe(entity, _entity, &vsp1->entities, list_dev) { 227 list_del(&entity->list_dev); 228 vsp1_entity_destroy(entity); 229 } 230 231 list_for_each_entry_safe(video, _video, &vsp1->videos, list) { 232 list_del(&video->list); 233 vsp1_video_cleanup(video); 234 } 235 236 v4l2_device_unregister(&vsp1->v4l2_dev); 237 if (vsp1->info->uapi) 238 media_device_unregister(&vsp1->media_dev); 239 media_device_cleanup(&vsp1->media_dev); 240 241 if (!vsp1->info->uapi) 242 vsp1_drm_cleanup(vsp1); 243 } 244 245 static int vsp1_create_entities(struct vsp1_device *vsp1) 246 { 247 struct media_device *mdev = &vsp1->media_dev; 248 struct v4l2_device *vdev = &vsp1->v4l2_dev; 249 struct vsp1_entity *entity; 250 unsigned int i; 251 int ret; 252 253 mdev->dev = vsp1->dev; 254 mdev->hw_revision = vsp1->version; 255 strscpy(mdev->model, vsp1->info->model, sizeof(mdev->model)); 256 media_device_init(mdev); 257 258 vsp1->media_ops.link_setup = vsp1_entity_link_setup; 259 /* 260 * Don't perform link validation when the userspace API is disabled as 261 * the pipeline is configured internally by the driver in that case, and 262 * its configuration can thus be trusted. 263 */ 264 if (vsp1->info->uapi) 265 vsp1->media_ops.link_validate = v4l2_subdev_link_validate; 266 267 vdev->mdev = mdev; 268 ret = v4l2_device_register(vsp1->dev, vdev); 269 if (ret < 0) { 270 dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n", 271 ret); 272 goto done; 273 } 274 275 /* Instantiate all the entities. */ 276 if (vsp1_feature(vsp1, VSP1_HAS_BRS)) { 277 vsp1->brs = vsp1_brx_create(vsp1, VSP1_ENTITY_BRS); 278 if (IS_ERR(vsp1->brs)) { 279 ret = PTR_ERR(vsp1->brs); 280 goto done; 281 } 282 283 list_add_tail(&vsp1->brs->entity.list_dev, &vsp1->entities); 284 } 285 286 if (vsp1_feature(vsp1, VSP1_HAS_BRU)) { 287 vsp1->bru = vsp1_brx_create(vsp1, VSP1_ENTITY_BRU); 288 if (IS_ERR(vsp1->bru)) { 289 ret = PTR_ERR(vsp1->bru); 290 goto done; 291 } 292 293 list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); 294 } 295 296 if (vsp1_feature(vsp1, VSP1_HAS_CLU)) { 297 vsp1->clu = vsp1_clu_create(vsp1); 298 if (IS_ERR(vsp1->clu)) { 299 ret = PTR_ERR(vsp1->clu); 300 goto done; 301 } 302 303 list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities); 304 } 305 306 vsp1->hsi = vsp1_hsit_create(vsp1, true); 307 if (IS_ERR(vsp1->hsi)) { 308 ret = PTR_ERR(vsp1->hsi); 309 goto done; 310 } 311 312 list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities); 313 314 vsp1->hst = vsp1_hsit_create(vsp1, false); 315 if (IS_ERR(vsp1->hst)) { 316 ret = PTR_ERR(vsp1->hst); 317 goto done; 318 } 319 320 list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); 321 322 if (vsp1_feature(vsp1, VSP1_HAS_HGO) && vsp1->info->uapi) { 323 vsp1->hgo = vsp1_hgo_create(vsp1); 324 if (IS_ERR(vsp1->hgo)) { 325 ret = PTR_ERR(vsp1->hgo); 326 goto done; 327 } 328 329 list_add_tail(&vsp1->hgo->histo.entity.list_dev, 330 &vsp1->entities); 331 } 332 333 if (vsp1_feature(vsp1, VSP1_HAS_HGT) && vsp1->info->uapi) { 334 vsp1->hgt = vsp1_hgt_create(vsp1); 335 if (IS_ERR(vsp1->hgt)) { 336 ret = PTR_ERR(vsp1->hgt); 337 goto done; 338 } 339 340 list_add_tail(&vsp1->hgt->histo.entity.list_dev, 341 &vsp1->entities); 342 } 343 344 /* 345 * The LIFs are only supported when used in conjunction with the DU, in 346 * which case the userspace API is disabled. If the userspace API is 347 * enabled skip the LIFs, even when present. 348 */ 349 if (!vsp1->info->uapi) { 350 for (i = 0; i < vsp1->info->lif_count; ++i) { 351 struct vsp1_lif *lif; 352 353 lif = vsp1_lif_create(vsp1, i); 354 if (IS_ERR(lif)) { 355 ret = PTR_ERR(lif); 356 goto done; 357 } 358 359 vsp1->lif[i] = lif; 360 list_add_tail(&lif->entity.list_dev, &vsp1->entities); 361 } 362 } 363 364 if (vsp1_feature(vsp1, VSP1_HAS_LUT)) { 365 vsp1->lut = vsp1_lut_create(vsp1); 366 if (IS_ERR(vsp1->lut)) { 367 ret = PTR_ERR(vsp1->lut); 368 goto done; 369 } 370 371 list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); 372 } 373 374 for (i = 0; i < vsp1->info->rpf_count; ++i) { 375 struct vsp1_rwpf *rpf; 376 377 rpf = vsp1_rpf_create(vsp1, i); 378 if (IS_ERR(rpf)) { 379 ret = PTR_ERR(rpf); 380 goto done; 381 } 382 383 vsp1->rpf[i] = rpf; 384 list_add_tail(&rpf->entity.list_dev, &vsp1->entities); 385 386 if (vsp1->info->uapi) { 387 struct vsp1_video *video = vsp1_video_create(vsp1, rpf); 388 389 if (IS_ERR(video)) { 390 ret = PTR_ERR(video); 391 goto done; 392 } 393 394 list_add_tail(&video->list, &vsp1->videos); 395 } 396 } 397 398 if (vsp1_feature(vsp1, VSP1_HAS_SRU)) { 399 vsp1->sru = vsp1_sru_create(vsp1); 400 if (IS_ERR(vsp1->sru)) { 401 ret = PTR_ERR(vsp1->sru); 402 goto done; 403 } 404 405 list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); 406 } 407 408 for (i = 0; i < vsp1->info->uds_count; ++i) { 409 struct vsp1_uds *uds; 410 411 uds = vsp1_uds_create(vsp1, i); 412 if (IS_ERR(uds)) { 413 ret = PTR_ERR(uds); 414 goto done; 415 } 416 417 vsp1->uds[i] = uds; 418 list_add_tail(&uds->entity.list_dev, &vsp1->entities); 419 } 420 421 for (i = 0; i < vsp1->info->uif_count; ++i) { 422 struct vsp1_uif *uif; 423 424 uif = vsp1_uif_create(vsp1, i); 425 if (IS_ERR(uif)) { 426 ret = PTR_ERR(uif); 427 goto done; 428 } 429 430 vsp1->uif[i] = uif; 431 list_add_tail(&uif->entity.list_dev, &vsp1->entities); 432 } 433 434 for (i = 0; i < vsp1->info->wpf_count; ++i) { 435 struct vsp1_rwpf *wpf; 436 437 wpf = vsp1_wpf_create(vsp1, i); 438 if (IS_ERR(wpf)) { 439 ret = PTR_ERR(wpf); 440 goto done; 441 } 442 443 vsp1->wpf[i] = wpf; 444 list_add_tail(&wpf->entity.list_dev, &vsp1->entities); 445 446 if (vsp1->info->uapi) { 447 struct vsp1_video *video = vsp1_video_create(vsp1, wpf); 448 449 if (IS_ERR(video)) { 450 ret = PTR_ERR(video); 451 goto done; 452 } 453 454 list_add_tail(&video->list, &vsp1->videos); 455 } 456 } 457 458 /* Register all subdevs. */ 459 list_for_each_entry(entity, &vsp1->entities, list_dev) { 460 ret = v4l2_device_register_subdev(&vsp1->v4l2_dev, 461 &entity->subdev); 462 if (ret < 0) 463 goto done; 464 } 465 466 /* 467 * Create links and register subdev nodes if the userspace API is 468 * enabled or initialize the DRM pipeline otherwise. 469 */ 470 if (vsp1->info->uapi) { 471 ret = vsp1_uapi_create_links(vsp1); 472 if (ret < 0) 473 goto done; 474 475 ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); 476 if (ret < 0) 477 goto done; 478 479 ret = media_device_register(mdev); 480 } else { 481 ret = vsp1_drm_init(vsp1); 482 } 483 484 done: 485 if (ret < 0) 486 vsp1_destroy_entities(vsp1); 487 488 return ret; 489 } 490 491 int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index) 492 { 493 unsigned int timeout; 494 u32 status; 495 496 status = vsp1_read(vsp1, VI6_STATUS); 497 if (!(status & VI6_STATUS_SYS_ACT(index))) 498 return 0; 499 500 vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index)); 501 for (timeout = 10; timeout > 0; --timeout) { 502 status = vsp1_read(vsp1, VI6_STATUS); 503 if (!(status & VI6_STATUS_SYS_ACT(index))) 504 break; 505 506 usleep_range(1000, 2000); 507 } 508 509 if (!timeout) { 510 dev_err(vsp1->dev, "failed to reset wpf.%u\n", index); 511 return -ETIMEDOUT; 512 } 513 514 return 0; 515 } 516 517 static int vsp1_device_init(struct vsp1_device *vsp1) 518 { 519 unsigned int i; 520 int ret; 521 522 /* Reset any channel that might be running. */ 523 for (i = 0; i < vsp1->info->wpf_count; ++i) { 524 ret = vsp1_reset_wpf(vsp1, i); 525 if (ret < 0) 526 return ret; 527 } 528 529 vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) | 530 (8 << VI6_CLK_DCSWT_CSTRW_SHIFT)); 531 532 for (i = 0; i < vsp1->info->rpf_count; ++i) 533 vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED); 534 535 for (i = 0; i < vsp1->info->uds_count; ++i) 536 vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED); 537 538 for (i = 0; i < vsp1->info->uif_count; ++i) 539 vsp1_write(vsp1, VI6_DPR_UIF_ROUTE(i), VI6_DPR_NODE_UNUSED); 540 541 vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED); 542 vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED); 543 vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED); 544 vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED); 545 vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED); 546 vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED); 547 548 if (vsp1_feature(vsp1, VSP1_HAS_BRS)) 549 vsp1_write(vsp1, VI6_DPR_ILV_BRS_ROUTE, VI6_DPR_NODE_UNUSED); 550 551 vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 552 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 553 vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 554 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 555 556 vsp1_dlm_setup(vsp1); 557 558 return 0; 559 } 560 561 static void vsp1_mask_all_interrupts(struct vsp1_device *vsp1) 562 { 563 unsigned int i; 564 565 for (i = 0; i < vsp1->info->lif_count; ++i) 566 vsp1_write(vsp1, VI6_DISP_IRQ_ENB(i), 0); 567 for (i = 0; i < vsp1->info->wpf_count; ++i) 568 vsp1_write(vsp1, VI6_WPF_IRQ_ENB(i), 0); 569 } 570 571 /* 572 * vsp1_device_get - Acquire the VSP1 device 573 * 574 * Make sure the device is not suspended and initialize it if needed. 575 * 576 * Return 0 on success or a negative error code otherwise. 577 */ 578 int vsp1_device_get(struct vsp1_device *vsp1) 579 { 580 return pm_runtime_resume_and_get(vsp1->dev); 581 } 582 583 /* 584 * vsp1_device_put - Release the VSP1 device 585 * 586 * Decrement the VSP1 reference count and cleanup the device if the last 587 * reference is released. 588 */ 589 void vsp1_device_put(struct vsp1_device *vsp1) 590 { 591 pm_runtime_put_sync(vsp1->dev); 592 } 593 594 /* ----------------------------------------------------------------------------- 595 * Power Management 596 */ 597 598 static int __maybe_unused vsp1_pm_suspend(struct device *dev) 599 { 600 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 601 602 /* 603 * When used as part of a display pipeline, the VSP is stopped and 604 * restarted explicitly by the DU. 605 */ 606 if (!vsp1->drm) 607 vsp1_video_suspend(vsp1); 608 609 pm_runtime_force_suspend(vsp1->dev); 610 611 return 0; 612 } 613 614 static int __maybe_unused vsp1_pm_resume(struct device *dev) 615 { 616 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 617 618 pm_runtime_force_resume(vsp1->dev); 619 620 /* 621 * When used as part of a display pipeline, the VSP is stopped and 622 * restarted explicitly by the DU. 623 */ 624 if (!vsp1->drm) 625 vsp1_video_resume(vsp1); 626 627 return 0; 628 } 629 630 static int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev) 631 { 632 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 633 634 rcar_fcp_disable(vsp1->fcp); 635 reset_control_assert(vsp1->rstc); 636 637 return 0; 638 } 639 640 static int __maybe_unused vsp1_pm_runtime_resume(struct device *dev) 641 { 642 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 643 int ret; 644 645 ret = reset_control_deassert(vsp1->rstc); 646 if (ret < 0) 647 return ret; 648 649 if (vsp1->info) { 650 /* 651 * On R-Car Gen2 and RZ/G1, vsp1 register access after deassert 652 * can cause lock-up. It is a special case and needs some delay 653 * to avoid this lock-up. 654 */ 655 if (vsp1->info->gen == 2) 656 udelay(1); 657 658 ret = vsp1_device_init(vsp1); 659 if (ret < 0) 660 goto done; 661 } 662 663 ret = rcar_fcp_enable(vsp1->fcp); 664 665 done: 666 if (ret < 0) 667 reset_control_assert(vsp1->rstc); 668 669 return ret; 670 } 671 672 static const struct dev_pm_ops vsp1_pm_ops = { 673 SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume) 674 SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL) 675 }; 676 677 /* ----------------------------------------------------------------------------- 678 * Platform Driver 679 */ 680 681 static const struct vsp1_device_info vsp1_device_infos[] = { 682 { 683 .version = VI6_IP_VERSION_MODEL_VSPS_H2, 684 .model = "VSP1-S", 685 .gen = 2, 686 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO 687 | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU 688 | VSP1_HAS_WPF_VFLIP, 689 .rpf_count = 5, 690 .uds_count = 3, 691 .wpf_count = 4, 692 .num_bru_inputs = 4, 693 .uapi = true, 694 }, { 695 .version = VI6_IP_VERSION_MODEL_VSPR_H2, 696 .model = "VSP1-R", 697 .gen = 2, 698 .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, 699 .rpf_count = 5, 700 .uds_count = 3, 701 .wpf_count = 4, 702 .num_bru_inputs = 4, 703 .uapi = true, 704 }, { 705 .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, 706 .model = "VSP1-D", 707 .gen = 2, 708 .features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LUT, 709 .lif_count = 1, 710 .rpf_count = 4, 711 .uds_count = 1, 712 .wpf_count = 1, 713 .num_bru_inputs = 4, 714 .uapi = true, 715 }, { 716 .version = VI6_IP_VERSION_MODEL_VSPS_M2, 717 .model = "VSP1-S", 718 .gen = 2, 719 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO 720 | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU 721 | VSP1_HAS_WPF_VFLIP, 722 .rpf_count = 5, 723 .uds_count = 1, 724 .wpf_count = 4, 725 .num_bru_inputs = 4, 726 .uapi = true, 727 }, { 728 .version = VI6_IP_VERSION_MODEL_VSPS_V2H, 729 .model = "VSP1V-S", 730 .gen = 2, 731 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT 732 | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, 733 .rpf_count = 4, 734 .uds_count = 1, 735 .wpf_count = 4, 736 .num_bru_inputs = 4, 737 .uapi = true, 738 }, { 739 .version = VI6_IP_VERSION_MODEL_VSPD_V2H, 740 .model = "VSP1V-D", 741 .gen = 2, 742 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT, 743 .lif_count = 1, 744 .rpf_count = 4, 745 .uds_count = 1, 746 .wpf_count = 1, 747 .num_bru_inputs = 4, 748 .uapi = true, 749 }, { 750 .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, 751 .model = "VSP2-I", 752 .gen = 3, 753 .features = VSP1_HAS_CLU | VSP1_HAS_HGO | VSP1_HAS_HGT 754 | VSP1_HAS_LUT | VSP1_HAS_SRU | VSP1_HAS_WPF_HFLIP 755 | VSP1_HAS_WPF_VFLIP, 756 .rpf_count = 1, 757 .uds_count = 1, 758 .wpf_count = 1, 759 .uapi = true, 760 }, { 761 .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, 762 .model = "VSP2-BD", 763 .gen = 3, 764 .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP, 765 .rpf_count = 5, 766 .wpf_count = 1, 767 .num_bru_inputs = 5, 768 .uapi = true, 769 }, { 770 .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, 771 .model = "VSP2-BC", 772 .gen = 3, 773 .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO 774 | VSP1_HAS_LUT | VSP1_HAS_WPF_VFLIP, 775 .rpf_count = 5, 776 .wpf_count = 1, 777 .num_bru_inputs = 5, 778 .uapi = true, 779 }, { 780 .version = VI6_IP_VERSION_MODEL_VSPBS_GEN3, 781 .model = "VSP2-BS", 782 .gen = 3, 783 .features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP, 784 .rpf_count = 2, 785 .wpf_count = 1, 786 .uapi = true, 787 }, { 788 .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, 789 .model = "VSP2-D", 790 .gen = 3, 791 .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP | VSP1_HAS_EXT_DL, 792 .lif_count = 1, 793 .rpf_count = 5, 794 .uif_count = 1, 795 .wpf_count = 2, 796 .num_bru_inputs = 5, 797 }, { 798 .version = VI6_IP_VERSION_MODEL_VSPD_V3, 799 .model = "VSP2-D", 800 .soc = VI6_IP_VERSION_SOC_V3H, 801 .gen = 3, 802 .features = VSP1_HAS_BRS | VSP1_HAS_BRU, 803 .lif_count = 1, 804 .rpf_count = 5, 805 .uif_count = 1, 806 .wpf_count = 1, 807 .num_bru_inputs = 5, 808 }, { 809 .version = VI6_IP_VERSION_MODEL_VSPD_V3, 810 .model = "VSP2-D", 811 .soc = VI6_IP_VERSION_SOC_V3M, 812 .gen = 3, 813 .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_NON_ZERO_LBA, 814 .lif_count = 1, 815 .rpf_count = 5, 816 .uif_count = 1, 817 .wpf_count = 1, 818 .num_bru_inputs = 5, 819 }, { 820 .version = VI6_IP_VERSION_MODEL_VSPDL_GEN3, 821 .model = "VSP2-DL", 822 .gen = 3, 823 .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_EXT_DL, 824 .lif_count = 2, 825 .rpf_count = 5, 826 .uif_count = 2, 827 .wpf_count = 2, 828 .num_bru_inputs = 5, 829 }, { 830 .version = VI6_IP_VERSION_MODEL_VSPD_GEN4, 831 .model = "VSP2-D", 832 .gen = 4, 833 .features = VSP1_HAS_BRU | VSP1_HAS_EXT_DL, 834 .lif_count = 1, 835 .rpf_count = 5, 836 .uif_count = 2, 837 .wpf_count = 1, 838 .num_bru_inputs = 5, 839 }, 840 }; 841 842 static const struct vsp1_device_info rzg2l_vsp2_device_info = { 843 .version = VI6_IP_VERSION_MODEL_VSPD_RZG2L, 844 .model = "VSP2-D", 845 .soc = VI6_IP_VERSION_SOC_RZG2L, 846 .gen = 3, 847 .features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP | VSP1_HAS_EXT_DL 848 | VSP1_HAS_NON_ZERO_LBA, 849 .lif_count = 1, 850 .rpf_count = 2, 851 .wpf_count = 1, 852 }; 853 854 static const struct vsp1_device_info *vsp1_lookup_info(struct vsp1_device *vsp1) 855 { 856 const struct vsp1_device_info *info; 857 unsigned int i; 858 u32 model; 859 u32 soc; 860 861 /* 862 * Try the info stored in match data first for devices that don't have 863 * a version register. 864 */ 865 info = of_device_get_match_data(vsp1->dev); 866 if (info) { 867 vsp1->version = VI6_IP_VERSION_VSP_SW | info->version | info->soc; 868 return info; 869 } 870 871 vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION); 872 model = vsp1->version & VI6_IP_VERSION_MODEL_MASK; 873 soc = vsp1->version & VI6_IP_VERSION_SOC_MASK; 874 875 for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { 876 info = &vsp1_device_infos[i]; 877 878 if (model == info->version && (!info->soc || soc == info->soc)) 879 return info; 880 } 881 882 dev_err(vsp1->dev, "unsupported IP version 0x%08x\n", vsp1->version); 883 884 return NULL; 885 } 886 887 static int vsp1_probe(struct platform_device *pdev) 888 { 889 struct vsp1_device *vsp1; 890 struct device_node *fcp_node; 891 int ret; 892 int irq; 893 894 vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL); 895 if (vsp1 == NULL) 896 return -ENOMEM; 897 898 vsp1->dev = &pdev->dev; 899 INIT_LIST_HEAD(&vsp1->entities); 900 INIT_LIST_HEAD(&vsp1->videos); 901 902 platform_set_drvdata(pdev, vsp1); 903 904 /* I/O and IRQ resources (clock managed by the clock PM domain). */ 905 vsp1->mmio = devm_platform_ioremap_resource(pdev, 0); 906 if (IS_ERR(vsp1->mmio)) 907 return PTR_ERR(vsp1->mmio); 908 909 irq = platform_get_irq(pdev, 0); 910 if (irq < 0) 911 return irq; 912 913 vsp1->rstc = devm_reset_control_get_shared(&pdev->dev, NULL); 914 if (IS_ERR(vsp1->rstc)) 915 return dev_err_probe(&pdev->dev, PTR_ERR(vsp1->rstc), 916 "failed to get reset control\n"); 917 918 /* FCP (optional). */ 919 fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0); 920 if (fcp_node) { 921 vsp1->fcp = rcar_fcp_get(fcp_node); 922 of_node_put(fcp_node); 923 if (IS_ERR(vsp1->fcp)) { 924 dev_dbg(&pdev->dev, "FCP not found (%ld)\n", 925 PTR_ERR(vsp1->fcp)); 926 return PTR_ERR(vsp1->fcp); 927 } 928 929 /* 930 * When the FCP is present, it handles all bus master accesses 931 * for the VSP and must thus be used in place of the VSP device 932 * to map DMA buffers. 933 */ 934 vsp1->bus_master = rcar_fcp_get_device(vsp1->fcp); 935 } else { 936 vsp1->bus_master = vsp1->dev; 937 } 938 939 /* Configure device parameters based on the version register. */ 940 pm_runtime_enable(&pdev->dev); 941 942 ret = vsp1_device_get(vsp1); 943 if (ret < 0) 944 goto done; 945 946 vsp1->info = vsp1_lookup_info(vsp1); 947 if (!vsp1->info) { 948 vsp1_device_put(vsp1); 949 ret = -ENXIO; 950 goto done; 951 } 952 953 dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version); 954 955 /* 956 * Previous use of the hardware (e.g. by the bootloader) could leave 957 * some interrupts enabled and pending. 958 * 959 * TODO: Investigate if this shouldn't be better handled by using the 960 * device reset provided by the CPG. 961 */ 962 vsp1_mask_all_interrupts(vsp1); 963 964 vsp1_device_put(vsp1); 965 966 ret = devm_request_irq(&pdev->dev, irq, vsp1_irq_handler, 967 IRQF_SHARED, dev_name(&pdev->dev), vsp1); 968 if (ret < 0) { 969 dev_err(&pdev->dev, "failed to request IRQ\n"); 970 goto done; 971 } 972 973 /* Instantiate entities. */ 974 ret = vsp1_create_entities(vsp1); 975 if (ret < 0) { 976 dev_err(&pdev->dev, "failed to create entities\n"); 977 goto done; 978 } 979 980 done: 981 if (ret) { 982 pm_runtime_disable(&pdev->dev); 983 rcar_fcp_put(vsp1->fcp); 984 } 985 986 return ret; 987 } 988 989 static void vsp1_remove(struct platform_device *pdev) 990 { 991 struct vsp1_device *vsp1 = platform_get_drvdata(pdev); 992 993 vsp1_destroy_entities(vsp1); 994 rcar_fcp_put(vsp1->fcp); 995 996 pm_runtime_disable(&pdev->dev); 997 } 998 999 static const struct of_device_id vsp1_of_match[] = { 1000 { .compatible = "renesas,vsp1" }, 1001 { .compatible = "renesas,vsp2" }, 1002 { .compatible = "renesas,r9a07g044-vsp2", .data = &rzg2l_vsp2_device_info }, 1003 { }, 1004 }; 1005 MODULE_DEVICE_TABLE(of, vsp1_of_match); 1006 1007 static struct platform_driver vsp1_platform_driver = { 1008 .probe = vsp1_probe, 1009 .remove_new = vsp1_remove, 1010 .driver = { 1011 .name = "vsp1", 1012 .pm = &vsp1_pm_ops, 1013 .of_match_table = vsp1_of_match, 1014 }, 1015 }; 1016 1017 module_platform_driver(vsp1_platform_driver); 1018 1019 MODULE_ALIAS("vsp1"); 1020 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 1021 MODULE_DESCRIPTION("Renesas VSP1 Driver"); 1022 MODULE_LICENSE("GPL"); 1023