1 /* 2 * Xilinx Video IP Composite Device 3 * 4 * Copyright (C) 2013-2015 Ideas on Board 5 * Copyright (C) 2013-2015 Xilinx, Inc. 6 * 7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> 8 * Laurent Pinchart <laurent.pinchart@ideasonboard.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15 #include <linux/list.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/of_graph.h> 19 #include <linux/platform_device.h> 20 #include <linux/slab.h> 21 22 #include <media/v4l2-async.h> 23 #include <media/v4l2-common.h> 24 #include <media/v4l2-device.h> 25 #include <media/v4l2-fwnode.h> 26 27 #include "xilinx-dma.h" 28 #include "xilinx-vipp.h" 29 30 #define XVIPP_DMA_S2MM 0 31 #define XVIPP_DMA_MM2S 1 32 33 /** 34 * struct xvip_graph_entity - Entity in the video graph 35 * @asd: subdev asynchronous registration information 36 * @entity: media entity, from the corresponding V4L2 subdev 37 * @subdev: V4L2 subdev 38 */ 39 struct xvip_graph_entity { 40 struct v4l2_async_subdev asd; /* must be first */ 41 struct media_entity *entity; 42 struct v4l2_subdev *subdev; 43 }; 44 45 static inline struct xvip_graph_entity * 46 to_xvip_entity(struct v4l2_async_subdev *asd) 47 { 48 return container_of(asd, struct xvip_graph_entity, asd); 49 } 50 51 /* ----------------------------------------------------------------------------- 52 * Graph Management 53 */ 54 55 static struct xvip_graph_entity * 56 xvip_graph_find_entity(struct xvip_composite_device *xdev, 57 const struct fwnode_handle *fwnode) 58 { 59 struct xvip_graph_entity *entity; 60 struct v4l2_async_subdev *asd; 61 62 list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) { 63 entity = to_xvip_entity(asd); 64 if (entity->asd.match.fwnode == fwnode) 65 return entity; 66 } 67 68 return NULL; 69 } 70 71 static int xvip_graph_build_one(struct xvip_composite_device *xdev, 72 struct xvip_graph_entity *entity) 73 { 74 u32 link_flags = MEDIA_LNK_FL_ENABLED; 75 struct media_entity *local = entity->entity; 76 struct media_entity *remote; 77 struct media_pad *local_pad; 78 struct media_pad *remote_pad; 79 struct xvip_graph_entity *ent; 80 struct v4l2_fwnode_link link; 81 struct fwnode_handle *ep = NULL; 82 int ret = 0; 83 84 dev_dbg(xdev->dev, "creating links for entity %s\n", local->name); 85 86 while (1) { 87 /* Get the next endpoint and parse its link. */ 88 ep = fwnode_graph_get_next_endpoint(entity->asd.match.fwnode, 89 ep); 90 if (ep == NULL) 91 break; 92 93 dev_dbg(xdev->dev, "processing endpoint %p\n", ep); 94 95 ret = v4l2_fwnode_parse_link(ep, &link); 96 if (ret < 0) { 97 dev_err(xdev->dev, "failed to parse link for %p\n", 98 ep); 99 continue; 100 } 101 102 /* Skip sink ports, they will be processed from the other end of 103 * the link. 104 */ 105 if (link.local_port >= local->num_pads) { 106 dev_err(xdev->dev, "invalid port number %u for %p\n", 107 link.local_port, link.local_node); 108 v4l2_fwnode_put_link(&link); 109 ret = -EINVAL; 110 break; 111 } 112 113 local_pad = &local->pads[link.local_port]; 114 115 if (local_pad->flags & MEDIA_PAD_FL_SINK) { 116 dev_dbg(xdev->dev, "skipping sink port %p:%u\n", 117 link.local_node, link.local_port); 118 v4l2_fwnode_put_link(&link); 119 continue; 120 } 121 122 /* Skip DMA engines, they will be processed separately. */ 123 if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) { 124 dev_dbg(xdev->dev, "skipping DMA port %p:%u\n", 125 link.local_node, link.local_port); 126 v4l2_fwnode_put_link(&link); 127 continue; 128 } 129 130 /* Find the remote entity. */ 131 ent = xvip_graph_find_entity(xdev, link.remote_node); 132 if (ent == NULL) { 133 dev_err(xdev->dev, "no entity found for %p\n", 134 link.remote_node); 135 v4l2_fwnode_put_link(&link); 136 ret = -ENODEV; 137 break; 138 } 139 140 remote = ent->entity; 141 142 if (link.remote_port >= remote->num_pads) { 143 dev_err(xdev->dev, "invalid port number %u on %p\n", 144 link.remote_port, link.remote_node); 145 v4l2_fwnode_put_link(&link); 146 ret = -EINVAL; 147 break; 148 } 149 150 remote_pad = &remote->pads[link.remote_port]; 151 152 v4l2_fwnode_put_link(&link); 153 154 /* Create the media link. */ 155 dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", 156 local->name, local_pad->index, 157 remote->name, remote_pad->index); 158 159 ret = media_create_pad_link(local, local_pad->index, 160 remote, remote_pad->index, 161 link_flags); 162 if (ret < 0) { 163 dev_err(xdev->dev, 164 "failed to create %s:%u -> %s:%u link\n", 165 local->name, local_pad->index, 166 remote->name, remote_pad->index); 167 break; 168 } 169 } 170 171 fwnode_handle_put(ep); 172 return ret; 173 } 174 175 static struct xvip_dma * 176 xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port) 177 { 178 struct xvip_dma *dma; 179 180 list_for_each_entry(dma, &xdev->dmas, list) { 181 if (dma->port == port) 182 return dma; 183 } 184 185 return NULL; 186 } 187 188 static int xvip_graph_build_dma(struct xvip_composite_device *xdev) 189 { 190 u32 link_flags = MEDIA_LNK_FL_ENABLED; 191 struct device_node *node = xdev->dev->of_node; 192 struct media_entity *source; 193 struct media_entity *sink; 194 struct media_pad *source_pad; 195 struct media_pad *sink_pad; 196 struct xvip_graph_entity *ent; 197 struct v4l2_fwnode_link link; 198 struct device_node *ep = NULL; 199 struct xvip_dma *dma; 200 int ret = 0; 201 202 dev_dbg(xdev->dev, "creating links for DMA engines\n"); 203 204 while (1) { 205 /* Get the next endpoint and parse its link. */ 206 ep = of_graph_get_next_endpoint(node, ep); 207 if (ep == NULL) 208 break; 209 210 dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep); 211 212 ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); 213 if (ret < 0) { 214 dev_err(xdev->dev, "failed to parse link for %pOF\n", 215 ep); 216 continue; 217 } 218 219 /* Find the DMA engine. */ 220 dma = xvip_graph_find_dma(xdev, link.local_port); 221 if (dma == NULL) { 222 dev_err(xdev->dev, "no DMA engine found for port %u\n", 223 link.local_port); 224 v4l2_fwnode_put_link(&link); 225 ret = -EINVAL; 226 break; 227 } 228 229 dev_dbg(xdev->dev, "creating link for DMA engine %s\n", 230 dma->video.name); 231 232 /* Find the remote entity. */ 233 ent = xvip_graph_find_entity(xdev, link.remote_node); 234 if (ent == NULL) { 235 dev_err(xdev->dev, "no entity found for %pOF\n", 236 to_of_node(link.remote_node)); 237 v4l2_fwnode_put_link(&link); 238 ret = -ENODEV; 239 break; 240 } 241 242 if (link.remote_port >= ent->entity->num_pads) { 243 dev_err(xdev->dev, "invalid port number %u on %pOF\n", 244 link.remote_port, 245 to_of_node(link.remote_node)); 246 v4l2_fwnode_put_link(&link); 247 ret = -EINVAL; 248 break; 249 } 250 251 if (dma->pad.flags & MEDIA_PAD_FL_SOURCE) { 252 source = &dma->video.entity; 253 source_pad = &dma->pad; 254 sink = ent->entity; 255 sink_pad = &sink->pads[link.remote_port]; 256 } else { 257 source = ent->entity; 258 source_pad = &source->pads[link.remote_port]; 259 sink = &dma->video.entity; 260 sink_pad = &dma->pad; 261 } 262 263 v4l2_fwnode_put_link(&link); 264 265 /* Create the media link. */ 266 dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", 267 source->name, source_pad->index, 268 sink->name, sink_pad->index); 269 270 ret = media_create_pad_link(source, source_pad->index, 271 sink, sink_pad->index, 272 link_flags); 273 if (ret < 0) { 274 dev_err(xdev->dev, 275 "failed to create %s:%u -> %s:%u link\n", 276 source->name, source_pad->index, 277 sink->name, sink_pad->index); 278 break; 279 } 280 } 281 282 of_node_put(ep); 283 return ret; 284 } 285 286 static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) 287 { 288 struct xvip_composite_device *xdev = 289 container_of(notifier, struct xvip_composite_device, notifier); 290 struct xvip_graph_entity *entity; 291 struct v4l2_async_subdev *asd; 292 int ret; 293 294 dev_dbg(xdev->dev, "notify complete, all subdevs registered\n"); 295 296 /* Create links for every entity. */ 297 list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) { 298 entity = to_xvip_entity(asd); 299 ret = xvip_graph_build_one(xdev, entity); 300 if (ret < 0) 301 return ret; 302 } 303 304 /* Create links for DMA channels. */ 305 ret = xvip_graph_build_dma(xdev); 306 if (ret < 0) 307 return ret; 308 309 ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev); 310 if (ret < 0) 311 dev_err(xdev->dev, "failed to register subdev nodes\n"); 312 313 return media_device_register(&xdev->media_dev); 314 } 315 316 static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, 317 struct v4l2_subdev *subdev, 318 struct v4l2_async_subdev *unused) 319 { 320 struct xvip_composite_device *xdev = 321 container_of(notifier, struct xvip_composite_device, notifier); 322 struct xvip_graph_entity *entity; 323 struct v4l2_async_subdev *asd; 324 325 /* Locate the entity corresponding to the bound subdev and store the 326 * subdev pointer. 327 */ 328 list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) { 329 entity = to_xvip_entity(asd); 330 331 if (entity->asd.match.fwnode != subdev->fwnode) 332 continue; 333 334 if (entity->subdev) { 335 dev_err(xdev->dev, "duplicate subdev for node %p\n", 336 entity->asd.match.fwnode); 337 return -EINVAL; 338 } 339 340 dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name); 341 entity->entity = &subdev->entity; 342 entity->subdev = subdev; 343 return 0; 344 } 345 346 dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name); 347 return -EINVAL; 348 } 349 350 static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = { 351 .bound = xvip_graph_notify_bound, 352 .complete = xvip_graph_notify_complete, 353 }; 354 355 static int xvip_graph_parse_one(struct xvip_composite_device *xdev, 356 struct fwnode_handle *fwnode) 357 { 358 struct fwnode_handle *remote; 359 struct fwnode_handle *ep = NULL; 360 int ret = 0; 361 362 dev_dbg(xdev->dev, "parsing node %p\n", fwnode); 363 364 while (1) { 365 struct v4l2_async_subdev *asd; 366 367 ep = fwnode_graph_get_next_endpoint(fwnode, ep); 368 if (ep == NULL) 369 break; 370 371 dev_dbg(xdev->dev, "handling endpoint %p\n", ep); 372 373 remote = fwnode_graph_get_remote_port_parent(ep); 374 if (remote == NULL) { 375 ret = -EINVAL; 376 goto err_notifier_cleanup; 377 } 378 379 fwnode_handle_put(ep); 380 381 /* Skip entities that we have already processed. */ 382 if (remote == of_fwnode_handle(xdev->dev->of_node) || 383 xvip_graph_find_entity(xdev, remote)) { 384 fwnode_handle_put(remote); 385 continue; 386 } 387 388 asd = v4l2_async_notifier_add_fwnode_subdev( 389 &xdev->notifier, remote, 390 sizeof(struct xvip_graph_entity)); 391 if (IS_ERR(asd)) { 392 ret = PTR_ERR(asd); 393 fwnode_handle_put(remote); 394 goto err_notifier_cleanup; 395 } 396 } 397 398 return 0; 399 400 err_notifier_cleanup: 401 v4l2_async_notifier_cleanup(&xdev->notifier); 402 fwnode_handle_put(ep); 403 return ret; 404 } 405 406 static int xvip_graph_parse(struct xvip_composite_device *xdev) 407 { 408 struct xvip_graph_entity *entity; 409 struct v4l2_async_subdev *asd; 410 int ret; 411 412 /* 413 * Walk the links to parse the full graph. Start by parsing the 414 * composite node and then parse entities in turn. The list_for_each 415 * loop will handle entities added at the end of the list while walking 416 * the links. 417 */ 418 ret = xvip_graph_parse_one(xdev, of_fwnode_handle(xdev->dev->of_node)); 419 if (ret < 0) 420 return 0; 421 422 list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) { 423 entity = to_xvip_entity(asd); 424 ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode); 425 if (ret < 0) { 426 v4l2_async_notifier_cleanup(&xdev->notifier); 427 break; 428 } 429 } 430 431 return ret; 432 } 433 434 static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, 435 struct device_node *node) 436 { 437 struct xvip_dma *dma; 438 enum v4l2_buf_type type; 439 const char *direction; 440 unsigned int index; 441 int ret; 442 443 ret = of_property_read_string(node, "direction", &direction); 444 if (ret < 0) 445 return ret; 446 447 if (strcmp(direction, "input") == 0) 448 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 449 else if (strcmp(direction, "output") == 0) 450 type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 451 else 452 return -EINVAL; 453 454 of_property_read_u32(node, "reg", &index); 455 456 dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL); 457 if (dma == NULL) 458 return -ENOMEM; 459 460 ret = xvip_dma_init(xdev, dma, type, index); 461 if (ret < 0) { 462 dev_err(xdev->dev, "%pOF initialization failed\n", node); 463 return ret; 464 } 465 466 list_add_tail(&dma->list, &xdev->dmas); 467 468 xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE 469 ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT; 470 471 return 0; 472 } 473 474 static int xvip_graph_dma_init(struct xvip_composite_device *xdev) 475 { 476 struct device_node *ports; 477 struct device_node *port; 478 int ret; 479 480 ports = of_get_child_by_name(xdev->dev->of_node, "ports"); 481 if (ports == NULL) { 482 dev_err(xdev->dev, "ports node not present\n"); 483 return -EINVAL; 484 } 485 486 for_each_child_of_node(ports, port) { 487 ret = xvip_graph_dma_init_one(xdev, port); 488 if (ret < 0) { 489 of_node_put(port); 490 return ret; 491 } 492 } 493 494 return 0; 495 } 496 497 static void xvip_graph_cleanup(struct xvip_composite_device *xdev) 498 { 499 struct xvip_dma *dmap; 500 struct xvip_dma *dma; 501 502 v4l2_async_notifier_unregister(&xdev->notifier); 503 v4l2_async_notifier_cleanup(&xdev->notifier); 504 505 list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) { 506 xvip_dma_cleanup(dma); 507 list_del(&dma->list); 508 } 509 } 510 511 static int xvip_graph_init(struct xvip_composite_device *xdev) 512 { 513 int ret; 514 515 /* Init the DMA channels. */ 516 ret = xvip_graph_dma_init(xdev); 517 if (ret < 0) { 518 dev_err(xdev->dev, "DMA initialization failed\n"); 519 goto done; 520 } 521 522 /* Parse the graph to extract a list of subdevice DT nodes. */ 523 ret = xvip_graph_parse(xdev); 524 if (ret < 0) { 525 dev_err(xdev->dev, "graph parsing failed\n"); 526 goto done; 527 } 528 529 if (list_empty(&xdev->notifier.asd_list)) { 530 dev_err(xdev->dev, "no subdev found in graph\n"); 531 goto done; 532 } 533 534 /* Register the subdevices notifier. */ 535 xdev->notifier.ops = &xvip_graph_notify_ops; 536 537 ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); 538 if (ret < 0) { 539 dev_err(xdev->dev, "notifier registration failed\n"); 540 goto done; 541 } 542 543 ret = 0; 544 545 done: 546 if (ret < 0) 547 xvip_graph_cleanup(xdev); 548 549 return ret; 550 } 551 552 /* ----------------------------------------------------------------------------- 553 * Media Controller and V4L2 554 */ 555 556 static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev) 557 { 558 v4l2_device_unregister(&xdev->v4l2_dev); 559 media_device_unregister(&xdev->media_dev); 560 media_device_cleanup(&xdev->media_dev); 561 } 562 563 static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) 564 { 565 int ret; 566 567 xdev->media_dev.dev = xdev->dev; 568 strscpy(xdev->media_dev.model, "Xilinx Video Composite Device", 569 sizeof(xdev->media_dev.model)); 570 xdev->media_dev.hw_revision = 0; 571 572 media_device_init(&xdev->media_dev); 573 574 xdev->v4l2_dev.mdev = &xdev->media_dev; 575 ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev); 576 if (ret < 0) { 577 dev_err(xdev->dev, "V4L2 device registration failed (%d)\n", 578 ret); 579 media_device_cleanup(&xdev->media_dev); 580 return ret; 581 } 582 583 return 0; 584 } 585 586 /* ----------------------------------------------------------------------------- 587 * Platform Device Driver 588 */ 589 590 static int xvip_composite_probe(struct platform_device *pdev) 591 { 592 struct xvip_composite_device *xdev; 593 int ret; 594 595 xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); 596 if (!xdev) 597 return -ENOMEM; 598 599 xdev->dev = &pdev->dev; 600 INIT_LIST_HEAD(&xdev->dmas); 601 v4l2_async_notifier_init(&xdev->notifier); 602 603 ret = xvip_composite_v4l2_init(xdev); 604 if (ret < 0) 605 return ret; 606 607 ret = xvip_graph_init(xdev); 608 if (ret < 0) 609 goto error; 610 611 platform_set_drvdata(pdev, xdev); 612 613 dev_info(xdev->dev, "device registered\n"); 614 615 return 0; 616 617 error: 618 xvip_composite_v4l2_cleanup(xdev); 619 return ret; 620 } 621 622 static int xvip_composite_remove(struct platform_device *pdev) 623 { 624 struct xvip_composite_device *xdev = platform_get_drvdata(pdev); 625 626 xvip_graph_cleanup(xdev); 627 xvip_composite_v4l2_cleanup(xdev); 628 629 return 0; 630 } 631 632 static const struct of_device_id xvip_composite_of_id_table[] = { 633 { .compatible = "xlnx,video" }, 634 { } 635 }; 636 MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table); 637 638 static struct platform_driver xvip_composite_driver = { 639 .driver = { 640 .name = "xilinx-video", 641 .of_match_table = xvip_composite_of_id_table, 642 }, 643 .probe = xvip_composite_probe, 644 .remove = xvip_composite_remove, 645 }; 646 647 module_platform_driver(xvip_composite_driver); 648 649 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 650 MODULE_DESCRIPTION("Xilinx Video IP Composite Driver"); 651 MODULE_LICENSE("GPL v2"); 652