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