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_WFP_IRQ_STA_DFE | VI6_WFP_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_WFP_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 snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", 247 dev_name(mdev->dev)); 248 media_device_init(mdev); 249 250 vsp1->media_ops.link_setup = vsp1_entity_link_setup; 251 /* 252 * Don't perform link validation when the userspace API is disabled as 253 * the pipeline is configured internally by the driver in that case, and 254 * its configuration can thus be trusted. 255 */ 256 if (vsp1->info->uapi) 257 vsp1->media_ops.link_validate = v4l2_subdev_link_validate; 258 259 vdev->mdev = mdev; 260 ret = v4l2_device_register(vsp1->dev, vdev); 261 if (ret < 0) { 262 dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n", 263 ret); 264 goto done; 265 } 266 267 /* Instantiate all the entities. */ 268 if (vsp1_feature(vsp1, VSP1_HAS_BRS)) { 269 vsp1->brs = vsp1_brx_create(vsp1, VSP1_ENTITY_BRS); 270 if (IS_ERR(vsp1->brs)) { 271 ret = PTR_ERR(vsp1->brs); 272 goto done; 273 } 274 275 list_add_tail(&vsp1->brs->entity.list_dev, &vsp1->entities); 276 } 277 278 if (vsp1_feature(vsp1, VSP1_HAS_BRU)) { 279 vsp1->bru = vsp1_brx_create(vsp1, VSP1_ENTITY_BRU); 280 if (IS_ERR(vsp1->bru)) { 281 ret = PTR_ERR(vsp1->bru); 282 goto done; 283 } 284 285 list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); 286 } 287 288 if (vsp1_feature(vsp1, VSP1_HAS_CLU)) { 289 vsp1->clu = vsp1_clu_create(vsp1); 290 if (IS_ERR(vsp1->clu)) { 291 ret = PTR_ERR(vsp1->clu); 292 goto done; 293 } 294 295 list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities); 296 } 297 298 vsp1->hsi = vsp1_hsit_create(vsp1, true); 299 if (IS_ERR(vsp1->hsi)) { 300 ret = PTR_ERR(vsp1->hsi); 301 goto done; 302 } 303 304 list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities); 305 306 vsp1->hst = vsp1_hsit_create(vsp1, false); 307 if (IS_ERR(vsp1->hst)) { 308 ret = PTR_ERR(vsp1->hst); 309 goto done; 310 } 311 312 list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); 313 314 if (vsp1_feature(vsp1, VSP1_HAS_HGO) && vsp1->info->uapi) { 315 vsp1->hgo = vsp1_hgo_create(vsp1); 316 if (IS_ERR(vsp1->hgo)) { 317 ret = PTR_ERR(vsp1->hgo); 318 goto done; 319 } 320 321 list_add_tail(&vsp1->hgo->histo.entity.list_dev, 322 &vsp1->entities); 323 } 324 325 if (vsp1_feature(vsp1, VSP1_HAS_HGT) && vsp1->info->uapi) { 326 vsp1->hgt = vsp1_hgt_create(vsp1); 327 if (IS_ERR(vsp1->hgt)) { 328 ret = PTR_ERR(vsp1->hgt); 329 goto done; 330 } 331 332 list_add_tail(&vsp1->hgt->histo.entity.list_dev, 333 &vsp1->entities); 334 } 335 336 /* 337 * The LIFs are only supported when used in conjunction with the DU, in 338 * which case the userspace API is disabled. If the userspace API is 339 * enabled skip the LIFs, even when present. 340 */ 341 if (!vsp1->info->uapi) { 342 for (i = 0; i < vsp1->info->lif_count; ++i) { 343 struct vsp1_lif *lif; 344 345 lif = vsp1_lif_create(vsp1, i); 346 if (IS_ERR(lif)) { 347 ret = PTR_ERR(lif); 348 goto done; 349 } 350 351 vsp1->lif[i] = lif; 352 list_add_tail(&lif->entity.list_dev, &vsp1->entities); 353 } 354 } 355 356 if (vsp1_feature(vsp1, VSP1_HAS_LUT)) { 357 vsp1->lut = vsp1_lut_create(vsp1); 358 if (IS_ERR(vsp1->lut)) { 359 ret = PTR_ERR(vsp1->lut); 360 goto done; 361 } 362 363 list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); 364 } 365 366 for (i = 0; i < vsp1->info->rpf_count; ++i) { 367 struct vsp1_rwpf *rpf; 368 369 rpf = vsp1_rpf_create(vsp1, i); 370 if (IS_ERR(rpf)) { 371 ret = PTR_ERR(rpf); 372 goto done; 373 } 374 375 vsp1->rpf[i] = rpf; 376 list_add_tail(&rpf->entity.list_dev, &vsp1->entities); 377 378 if (vsp1->info->uapi) { 379 struct vsp1_video *video = vsp1_video_create(vsp1, rpf); 380 381 if (IS_ERR(video)) { 382 ret = PTR_ERR(video); 383 goto done; 384 } 385 386 list_add_tail(&video->list, &vsp1->videos); 387 } 388 } 389 390 if (vsp1_feature(vsp1, VSP1_HAS_SRU)) { 391 vsp1->sru = vsp1_sru_create(vsp1); 392 if (IS_ERR(vsp1->sru)) { 393 ret = PTR_ERR(vsp1->sru); 394 goto done; 395 } 396 397 list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); 398 } 399 400 for (i = 0; i < vsp1->info->uds_count; ++i) { 401 struct vsp1_uds *uds; 402 403 uds = vsp1_uds_create(vsp1, i); 404 if (IS_ERR(uds)) { 405 ret = PTR_ERR(uds); 406 goto done; 407 } 408 409 vsp1->uds[i] = uds; 410 list_add_tail(&uds->entity.list_dev, &vsp1->entities); 411 } 412 413 for (i = 0; i < vsp1->info->uif_count; ++i) { 414 struct vsp1_uif *uif; 415 416 uif = vsp1_uif_create(vsp1, i); 417 if (IS_ERR(uif)) { 418 ret = PTR_ERR(uif); 419 goto done; 420 } 421 422 vsp1->uif[i] = uif; 423 list_add_tail(&uif->entity.list_dev, &vsp1->entities); 424 } 425 426 for (i = 0; i < vsp1->info->wpf_count; ++i) { 427 struct vsp1_rwpf *wpf; 428 429 wpf = vsp1_wpf_create(vsp1, i); 430 if (IS_ERR(wpf)) { 431 ret = PTR_ERR(wpf); 432 goto done; 433 } 434 435 vsp1->wpf[i] = wpf; 436 list_add_tail(&wpf->entity.list_dev, &vsp1->entities); 437 438 if (vsp1->info->uapi) { 439 struct vsp1_video *video = vsp1_video_create(vsp1, wpf); 440 441 if (IS_ERR(video)) { 442 ret = PTR_ERR(video); 443 goto done; 444 } 445 446 list_add_tail(&video->list, &vsp1->videos); 447 } 448 } 449 450 /* Register all subdevs. */ 451 list_for_each_entry(entity, &vsp1->entities, list_dev) { 452 ret = v4l2_device_register_subdev(&vsp1->v4l2_dev, 453 &entity->subdev); 454 if (ret < 0) 455 goto done; 456 } 457 458 /* 459 * Create links and register subdev nodes if the userspace API is 460 * enabled or initialize the DRM pipeline otherwise. 461 */ 462 if (vsp1->info->uapi) { 463 ret = vsp1_uapi_create_links(vsp1); 464 if (ret < 0) 465 goto done; 466 467 ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); 468 if (ret < 0) 469 goto done; 470 471 ret = media_device_register(mdev); 472 } else { 473 ret = vsp1_drm_init(vsp1); 474 } 475 476done: 477 if (ret < 0) 478 vsp1_destroy_entities(vsp1); 479 480 return ret; 481} 482 483int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index) 484{ 485 unsigned int timeout; 486 u32 status; 487 488 status = vsp1_read(vsp1, VI6_STATUS); 489 if (!(status & VI6_STATUS_SYS_ACT(index))) 490 return 0; 491 492 vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index)); 493 for (timeout = 10; timeout > 0; --timeout) { 494 status = vsp1_read(vsp1, VI6_STATUS); 495 if (!(status & VI6_STATUS_SYS_ACT(index))) 496 break; 497 498 usleep_range(1000, 2000); 499 } 500 501 if (!timeout) { 502 dev_err(vsp1->dev, "failed to reset wpf.%u\n", index); 503 return -ETIMEDOUT; 504 } 505 506 return 0; 507} 508 509static int vsp1_device_init(struct vsp1_device *vsp1) 510{ 511 unsigned int i; 512 int ret; 513 514 /* Reset any channel that might be running. */ 515 for (i = 0; i < vsp1->info->wpf_count; ++i) { 516 ret = vsp1_reset_wpf(vsp1, i); 517 if (ret < 0) 518 return ret; 519 } 520 521 vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) | 522 (8 << VI6_CLK_DCSWT_CSTRW_SHIFT)); 523 524 for (i = 0; i < vsp1->info->rpf_count; ++i) 525 vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED); 526 527 for (i = 0; i < vsp1->info->uds_count; ++i) 528 vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED); 529 530 for (i = 0; i < vsp1->info->uif_count; ++i) 531 vsp1_write(vsp1, VI6_DPR_UIF_ROUTE(i), VI6_DPR_NODE_UNUSED); 532 533 vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED); 534 vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED); 535 vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED); 536 vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED); 537 vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED); 538 vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED); 539 540 if (vsp1_feature(vsp1, VSP1_HAS_BRS)) 541 vsp1_write(vsp1, VI6_DPR_ILV_BRS_ROUTE, VI6_DPR_NODE_UNUSED); 542 543 vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 544 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 545 vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 546 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 547 548 vsp1_dlm_setup(vsp1); 549 550 return 0; 551} 552 553/* 554 * vsp1_device_get - Acquire the VSP1 device 555 * 556 * Make sure the device is not suspended and initialize it if needed. 557 * 558 * Return 0 on success or a negative error code otherwise. 559 */ 560int vsp1_device_get(struct vsp1_device *vsp1) 561{ 562 int ret; 563 564 ret = pm_runtime_get_sync(vsp1->dev); 565 if (ret < 0) { 566 pm_runtime_put_noidle(vsp1->dev); 567 return ret; 568 } 569 570 return 0; 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}; 790 791static int vsp1_probe(struct platform_device *pdev) 792{ 793 struct vsp1_device *vsp1; 794 struct device_node *fcp_node; 795 struct resource *irq; 796 struct resource *io; 797 unsigned int i; 798 int ret; 799 800 vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL); 801 if (vsp1 == NULL) 802 return -ENOMEM; 803 804 vsp1->dev = &pdev->dev; 805 INIT_LIST_HEAD(&vsp1->entities); 806 INIT_LIST_HEAD(&vsp1->videos); 807 808 platform_set_drvdata(pdev, vsp1); 809 810 /* I/O and IRQ resources (clock managed by the clock PM domain). */ 811 io = platform_get_resource(pdev, IORESOURCE_MEM, 0); 812 vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); 813 if (IS_ERR(vsp1->mmio)) 814 return PTR_ERR(vsp1->mmio); 815 816 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 817 if (!irq) { 818 dev_err(&pdev->dev, "missing IRQ\n"); 819 return -EINVAL; 820 } 821 822 ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler, 823 IRQF_SHARED, dev_name(&pdev->dev), vsp1); 824 if (ret < 0) { 825 dev_err(&pdev->dev, "failed to request IRQ\n"); 826 return ret; 827 } 828 829 /* FCP (optional). */ 830 fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0); 831 if (fcp_node) { 832 vsp1->fcp = rcar_fcp_get(fcp_node); 833 of_node_put(fcp_node); 834 if (IS_ERR(vsp1->fcp)) { 835 dev_dbg(&pdev->dev, "FCP not found (%ld)\n", 836 PTR_ERR(vsp1->fcp)); 837 return PTR_ERR(vsp1->fcp); 838 } 839 840 /* 841 * When the FCP is present, it handles all bus master accesses 842 * for the VSP and must thus be used in place of the VSP device 843 * to map DMA buffers. 844 */ 845 vsp1->bus_master = rcar_fcp_get_device(vsp1->fcp); 846 } else { 847 vsp1->bus_master = vsp1->dev; 848 } 849 850 /* Configure device parameters based on the version register. */ 851 pm_runtime_enable(&pdev->dev); 852 853 ret = vsp1_device_get(vsp1); 854 if (ret < 0) 855 goto done; 856 857 vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION); 858 vsp1_device_put(vsp1); 859 860 for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { 861 if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) == 862 vsp1_device_infos[i].version) { 863 vsp1->info = &vsp1_device_infos[i]; 864 break; 865 } 866 } 867 868 if (!vsp1->info) { 869 dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", 870 vsp1->version); 871 ret = -ENXIO; 872 goto done; 873 } 874 875 dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version); 876 877 /* Instantiate entities. */ 878 ret = vsp1_create_entities(vsp1); 879 if (ret < 0) { 880 dev_err(&pdev->dev, "failed to create entities\n"); 881 goto done; 882 } 883 884done: 885 if (ret) { 886 pm_runtime_disable(&pdev->dev); 887 rcar_fcp_put(vsp1->fcp); 888 } 889 890 return ret; 891} 892 893static int vsp1_remove(struct platform_device *pdev) 894{ 895 struct vsp1_device *vsp1 = platform_get_drvdata(pdev); 896 897 vsp1_destroy_entities(vsp1); 898 rcar_fcp_put(vsp1->fcp); 899 900 pm_runtime_disable(&pdev->dev); 901 902 return 0; 903} 904 905static const struct of_device_id vsp1_of_match[] = { 906 { .compatible = "renesas,vsp1" }, 907 { .compatible = "renesas,vsp2" }, 908 { }, 909}; 910MODULE_DEVICE_TABLE(of, vsp1_of_match); 911 912static struct platform_driver vsp1_platform_driver = { 913 .probe = vsp1_probe, 914 .remove = vsp1_remove, 915 .driver = { 916 .name = "vsp1", 917 .pm = &vsp1_pm_ops, 918 .of_match_table = vsp1_of_match, 919 }, 920}; 921 922module_platform_driver(vsp1_platform_driver); 923 924MODULE_ALIAS("vsp1"); 925MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 926MODULE_DESCRIPTION("Renesas VSP1 Driver"); 927MODULE_LICENSE("GPL"); 928