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 * @list: list entry in a graph entities list 36 * @node: the entity's DT node 37 * @entity: media entity, from the corresponding V4L2 subdev 38 * @asd: subdev asynchronous registration information 39 * @subdev: V4L2 subdev 40 */ 41 struct xvip_graph_entity { 42 struct list_head list; 43 struct device_node *node; 44 struct media_entity *entity; 45 46 struct v4l2_async_subdev asd; 47 struct v4l2_subdev *subdev; 48 }; 49 50 /* ----------------------------------------------------------------------------- 51 * Graph Management 52 */ 53 54 static struct xvip_graph_entity * 55 xvip_graph_find_entity(struct xvip_composite_device *xdev, 56 const struct device_node *node) 57 { 58 struct xvip_graph_entity *entity; 59 60 list_for_each_entry(entity, &xdev->entities, list) { 61 if (entity->node == node) 62 return entity; 63 } 64 65 return NULL; 66 } 67 68 static int xvip_graph_build_one(struct xvip_composite_device *xdev, 69 struct xvip_graph_entity *entity) 70 { 71 u32 link_flags = MEDIA_LNK_FL_ENABLED; 72 struct media_entity *local = entity->entity; 73 struct media_entity *remote; 74 struct media_pad *local_pad; 75 struct media_pad *remote_pad; 76 struct xvip_graph_entity *ent; 77 struct v4l2_fwnode_link link; 78 struct device_node *ep = NULL; 79 int ret = 0; 80 81 dev_dbg(xdev->dev, "creating links for entity %s\n", local->name); 82 83 while (1) { 84 /* Get the next endpoint and parse its link. */ 85 ep = of_graph_get_next_endpoint(entity->node, ep); 86 if (ep == NULL) 87 break; 88 89 dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep); 90 91 ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); 92 if (ret < 0) { 93 dev_err(xdev->dev, "failed to parse link for %pOF\n", 94 ep); 95 continue; 96 } 97 98 /* Skip sink ports, they will be processed from the other end of 99 * the link. 100 */ 101 if (link.local_port >= local->num_pads) { 102 dev_err(xdev->dev, "invalid port number %u for %pOF\n", 103 link.local_port, 104 to_of_node(link.local_node)); 105 v4l2_fwnode_put_link(&link); 106 ret = -EINVAL; 107 break; 108 } 109 110 local_pad = &local->pads[link.local_port]; 111 112 if (local_pad->flags & MEDIA_PAD_FL_SINK) { 113 dev_dbg(xdev->dev, "skipping sink port %pOF:%u\n", 114 to_of_node(link.local_node), 115 link.local_port); 116 v4l2_fwnode_put_link(&link); 117 continue; 118 } 119 120 /* Skip DMA engines, they will be processed separately. */ 121 if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) { 122 dev_dbg(xdev->dev, "skipping DMA port %pOF:%u\n", 123 to_of_node(link.local_node), 124 link.local_port); 125 v4l2_fwnode_put_link(&link); 126 continue; 127 } 128 129 /* Find the remote entity. */ 130 ent = xvip_graph_find_entity(xdev, 131 to_of_node(link.remote_node)); 132 if (ent == NULL) { 133 dev_err(xdev->dev, "no entity found for %pOF\n", 134 to_of_node(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 %pOF\n", 144 link.remote_port, to_of_node(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 of_node_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, 234 to_of_node(link.remote_node)); 235 if (ent == NULL) { 236 dev_err(xdev->dev, "no entity found for %pOF\n", 237 to_of_node(link.remote_node)); 238 v4l2_fwnode_put_link(&link); 239 ret = -ENODEV; 240 break; 241 } 242 243 if (link.remote_port >= ent->entity->num_pads) { 244 dev_err(xdev->dev, "invalid port number %u on %pOF\n", 245 link.remote_port, 246 to_of_node(link.remote_node)); 247 v4l2_fwnode_put_link(&link); 248 ret = -EINVAL; 249 break; 250 } 251 252 if (dma->pad.flags & MEDIA_PAD_FL_SOURCE) { 253 source = &dma->video.entity; 254 source_pad = &dma->pad; 255 sink = ent->entity; 256 sink_pad = &sink->pads[link.remote_port]; 257 } else { 258 source = ent->entity; 259 source_pad = &source->pads[link.remote_port]; 260 sink = &dma->video.entity; 261 sink_pad = &dma->pad; 262 } 263 264 v4l2_fwnode_put_link(&link); 265 266 /* Create the media link. */ 267 dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", 268 source->name, source_pad->index, 269 sink->name, sink_pad->index); 270 271 ret = media_create_pad_link(source, source_pad->index, 272 sink, sink_pad->index, 273 link_flags); 274 if (ret < 0) { 275 dev_err(xdev->dev, 276 "failed to create %s:%u -> %s:%u link\n", 277 source->name, source_pad->index, 278 sink->name, sink_pad->index); 279 break; 280 } 281 } 282 283 of_node_put(ep); 284 return ret; 285 } 286 287 static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) 288 { 289 struct xvip_composite_device *xdev = 290 container_of(notifier, struct xvip_composite_device, notifier); 291 struct xvip_graph_entity *entity; 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(entity, &xdev->entities, list) { 298 ret = xvip_graph_build_one(xdev, entity); 299 if (ret < 0) 300 return ret; 301 } 302 303 /* Create links for DMA channels. */ 304 ret = xvip_graph_build_dma(xdev); 305 if (ret < 0) 306 return ret; 307 308 ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev); 309 if (ret < 0) 310 dev_err(xdev->dev, "failed to register subdev nodes\n"); 311 312 return media_device_register(&xdev->media_dev); 313 } 314 315 static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, 316 struct v4l2_subdev *subdev, 317 struct v4l2_async_subdev *asd) 318 { 319 struct xvip_composite_device *xdev = 320 container_of(notifier, struct xvip_composite_device, notifier); 321 struct xvip_graph_entity *entity; 322 323 /* Locate the entity corresponding to the bound subdev and store the 324 * subdev pointer. 325 */ 326 list_for_each_entry(entity, &xdev->entities, list) { 327 if (entity->node != subdev->dev->of_node) 328 continue; 329 330 if (entity->subdev) { 331 dev_err(xdev->dev, "duplicate subdev for node %pOF\n", 332 entity->node); 333 return -EINVAL; 334 } 335 336 dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name); 337 entity->entity = &subdev->entity; 338 entity->subdev = subdev; 339 return 0; 340 } 341 342 dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name); 343 return -EINVAL; 344 } 345 346 static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = { 347 .bound = xvip_graph_notify_bound, 348 .complete = xvip_graph_notify_complete, 349 }; 350 351 static int xvip_graph_parse_one(struct xvip_composite_device *xdev, 352 struct device_node *node) 353 { 354 struct xvip_graph_entity *entity; 355 struct device_node *remote; 356 struct device_node *ep = NULL; 357 int ret = 0; 358 359 dev_dbg(xdev->dev, "parsing node %pOF\n", node); 360 361 while (1) { 362 ep = of_graph_get_next_endpoint(node, ep); 363 if (ep == NULL) 364 break; 365 366 dev_dbg(xdev->dev, "handling endpoint %pOF\n", ep); 367 368 remote = of_graph_get_remote_port_parent(ep); 369 if (remote == NULL) { 370 ret = -EINVAL; 371 break; 372 } 373 374 /* Skip entities that we have already processed. */ 375 if (remote == xdev->dev->of_node || 376 xvip_graph_find_entity(xdev, remote)) { 377 of_node_put(remote); 378 continue; 379 } 380 381 entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL); 382 if (entity == NULL) { 383 of_node_put(remote); 384 ret = -ENOMEM; 385 break; 386 } 387 388 entity->node = remote; 389 entity->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; 390 entity->asd.match.fwnode.fwnode = of_fwnode_handle(remote); 391 list_add_tail(&entity->list, &xdev->entities); 392 xdev->num_subdevs++; 393 } 394 395 of_node_put(ep); 396 return ret; 397 } 398 399 static int xvip_graph_parse(struct xvip_composite_device *xdev) 400 { 401 struct xvip_graph_entity *entity; 402 int ret; 403 404 /* 405 * Walk the links to parse the full graph. Start by parsing the 406 * composite node and then parse entities in turn. The list_for_each 407 * loop will handle entities added at the end of the list while walking 408 * the links. 409 */ 410 ret = xvip_graph_parse_one(xdev, xdev->dev->of_node); 411 if (ret < 0) 412 return 0; 413 414 list_for_each_entry(entity, &xdev->entities, list) { 415 ret = xvip_graph_parse_one(xdev, entity->node); 416 if (ret < 0) 417 break; 418 } 419 420 return ret; 421 } 422 423 static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, 424 struct device_node *node) 425 { 426 struct xvip_dma *dma; 427 enum v4l2_buf_type type; 428 const char *direction; 429 unsigned int index; 430 int ret; 431 432 ret = of_property_read_string(node, "direction", &direction); 433 if (ret < 0) 434 return ret; 435 436 if (strcmp(direction, "input") == 0) 437 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 438 else if (strcmp(direction, "output") == 0) 439 type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 440 else 441 return -EINVAL; 442 443 of_property_read_u32(node, "reg", &index); 444 445 dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL); 446 if (dma == NULL) 447 return -ENOMEM; 448 449 ret = xvip_dma_init(xdev, dma, type, index); 450 if (ret < 0) { 451 dev_err(xdev->dev, "%pOF initialization failed\n", node); 452 return ret; 453 } 454 455 list_add_tail(&dma->list, &xdev->dmas); 456 457 xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE 458 ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT; 459 460 return 0; 461 } 462 463 static int xvip_graph_dma_init(struct xvip_composite_device *xdev) 464 { 465 struct device_node *ports; 466 struct device_node *port; 467 int ret; 468 469 ports = of_get_child_by_name(xdev->dev->of_node, "ports"); 470 if (ports == NULL) { 471 dev_err(xdev->dev, "ports node not present\n"); 472 return -EINVAL; 473 } 474 475 for_each_child_of_node(ports, port) { 476 ret = xvip_graph_dma_init_one(xdev, port); 477 if (ret < 0) { 478 of_node_put(port); 479 return ret; 480 } 481 } 482 483 return 0; 484 } 485 486 static void xvip_graph_cleanup(struct xvip_composite_device *xdev) 487 { 488 struct xvip_graph_entity *entityp; 489 struct xvip_graph_entity *entity; 490 struct xvip_dma *dmap; 491 struct xvip_dma *dma; 492 493 v4l2_async_notifier_unregister(&xdev->notifier); 494 495 list_for_each_entry_safe(entity, entityp, &xdev->entities, list) { 496 of_node_put(entity->node); 497 list_del(&entity->list); 498 } 499 500 list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) { 501 xvip_dma_cleanup(dma); 502 list_del(&dma->list); 503 } 504 } 505 506 static int xvip_graph_init(struct xvip_composite_device *xdev) 507 { 508 struct xvip_graph_entity *entity; 509 struct v4l2_async_subdev **subdevs = NULL; 510 unsigned int num_subdevs; 511 unsigned int i; 512 int ret; 513 514 /* Init the DMA channels. */ 515 ret = xvip_graph_dma_init(xdev); 516 if (ret < 0) { 517 dev_err(xdev->dev, "DMA initialization failed\n"); 518 goto done; 519 } 520 521 /* Parse the graph to extract a list of subdevice DT nodes. */ 522 ret = xvip_graph_parse(xdev); 523 if (ret < 0) { 524 dev_err(xdev->dev, "graph parsing failed\n"); 525 goto done; 526 } 527 528 if (!xdev->num_subdevs) { 529 dev_err(xdev->dev, "no subdev found in graph\n"); 530 goto done; 531 } 532 533 /* Register the subdevices notifier. */ 534 num_subdevs = xdev->num_subdevs; 535 subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs, 536 GFP_KERNEL); 537 if (subdevs == NULL) { 538 ret = -ENOMEM; 539 goto done; 540 } 541 542 i = 0; 543 list_for_each_entry(entity, &xdev->entities, list) 544 subdevs[i++] = &entity->asd; 545 546 xdev->notifier.subdevs = subdevs; 547 xdev->notifier.num_subdevs = num_subdevs; 548 xdev->notifier.ops = &xvip_graph_notify_ops; 549 550 ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); 551 if (ret < 0) { 552 dev_err(xdev->dev, "notifier registration failed\n"); 553 goto done; 554 } 555 556 ret = 0; 557 558 done: 559 if (ret < 0) 560 xvip_graph_cleanup(xdev); 561 562 return ret; 563 } 564 565 /* ----------------------------------------------------------------------------- 566 * Media Controller and V4L2 567 */ 568 569 static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev) 570 { 571 v4l2_device_unregister(&xdev->v4l2_dev); 572 media_device_unregister(&xdev->media_dev); 573 media_device_cleanup(&xdev->media_dev); 574 } 575 576 static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) 577 { 578 int ret; 579 580 xdev->media_dev.dev = xdev->dev; 581 strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device", 582 sizeof(xdev->media_dev.model)); 583 xdev->media_dev.hw_revision = 0; 584 585 media_device_init(&xdev->media_dev); 586 587 xdev->v4l2_dev.mdev = &xdev->media_dev; 588 ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev); 589 if (ret < 0) { 590 dev_err(xdev->dev, "V4L2 device registration failed (%d)\n", 591 ret); 592 media_device_cleanup(&xdev->media_dev); 593 return ret; 594 } 595 596 return 0; 597 } 598 599 /* ----------------------------------------------------------------------------- 600 * Platform Device Driver 601 */ 602 603 static int xvip_composite_probe(struct platform_device *pdev) 604 { 605 struct xvip_composite_device *xdev; 606 int ret; 607 608 xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); 609 if (!xdev) 610 return -ENOMEM; 611 612 xdev->dev = &pdev->dev; 613 INIT_LIST_HEAD(&xdev->entities); 614 INIT_LIST_HEAD(&xdev->dmas); 615 616 ret = xvip_composite_v4l2_init(xdev); 617 if (ret < 0) 618 return ret; 619 620 ret = xvip_graph_init(xdev); 621 if (ret < 0) 622 goto error; 623 624 platform_set_drvdata(pdev, xdev); 625 626 dev_info(xdev->dev, "device registered\n"); 627 628 return 0; 629 630 error: 631 xvip_composite_v4l2_cleanup(xdev); 632 return ret; 633 } 634 635 static int xvip_composite_remove(struct platform_device *pdev) 636 { 637 struct xvip_composite_device *xdev = platform_get_drvdata(pdev); 638 639 xvip_graph_cleanup(xdev); 640 xvip_composite_v4l2_cleanup(xdev); 641 642 return 0; 643 } 644 645 static const struct of_device_id xvip_composite_of_id_table[] = { 646 { .compatible = "xlnx,video" }, 647 { } 648 }; 649 MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table); 650 651 static struct platform_driver xvip_composite_driver = { 652 .driver = { 653 .name = "xilinx-video", 654 .of_match_table = xvip_composite_of_id_table, 655 }, 656 .probe = xvip_composite_probe, 657 .remove = xvip_composite_remove, 658 }; 659 660 module_platform_driver(xvip_composite_driver); 661 662 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 663 MODULE_DESCRIPTION("Xilinx Video IP Composite Driver"); 664 MODULE_LICENSE("GPL v2"); 665