1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Driver for STM32 Digital Camera Memory Interface Pixel Processor 4 * 5 * Copyright (C) STMicroelectronics SA 2023 6 * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com> 7 * Alain Volmat <alain.volmat@foss.st.com> 8 * for STMicroelectronics. 9 */ 10 11#include <linux/clk.h> 12#include <linux/delay.h> 13#include <linux/init.h> 14#include <linux/module.h> 15#include <linux/pinctrl/consumer.h> 16#include <linux/platform_device.h> 17#include <linux/pm_runtime.h> 18#include <linux/property.h> 19#include <linux/reset.h> 20#include <media/media-device.h> 21#include <media/v4l2-device.h> 22#include <media/v4l2-fwnode.h> 23 24#include "dcmipp-common.h" 25 26#define DCMIPP_MDEV_MODEL_NAME "DCMIPP MDEV" 27 28#define DCMIPP_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ 29 .src_ent = src, \ 30 .src_pad = srcpad, \ 31 .sink_ent = sink, \ 32 .sink_pad = sinkpad, \ 33 .flags = link_flags, \ 34} 35 36struct dcmipp_device { 37 /* The platform device */ 38 struct platform_device pdev; 39 struct device *dev; 40 41 /* Hardware resources */ 42 void __iomem *regs; 43 struct clk *kclk; 44 45 /* The pipeline configuration */ 46 const struct dcmipp_pipeline_config *pipe_cfg; 47 48 /* The Associated media_device parent */ 49 struct media_device mdev; 50 51 /* Internal v4l2 parent device*/ 52 struct v4l2_device v4l2_dev; 53 54 /* Entities */ 55 struct dcmipp_ent_device **entity; 56 57 struct v4l2_async_notifier notifier; 58}; 59 60static inline struct dcmipp_device * 61notifier_to_dcmipp(struct v4l2_async_notifier *n) 62{ 63 return container_of(n, struct dcmipp_device, notifier); 64} 65 66/* Structure which describes individual configuration for each entity */ 67struct dcmipp_ent_config { 68 const char *name; 69 struct dcmipp_ent_device *(*init) 70 (struct device *dev, const char *entity_name, 71 struct v4l2_device *v4l2_dev, void __iomem *regs); 72 void (*release)(struct dcmipp_ent_device *ved); 73}; 74 75/* Structure which describes links between entities */ 76struct dcmipp_ent_link { 77 unsigned int src_ent; 78 u16 src_pad; 79 unsigned int sink_ent; 80 u16 sink_pad; 81 u32 flags; 82}; 83 84/* Structure which describes the whole topology */ 85struct dcmipp_pipeline_config { 86 const struct dcmipp_ent_config *ents; 87 size_t num_ents; 88 const struct dcmipp_ent_link *links; 89 size_t num_links; 90}; 91 92/* -------------------------------------------------------------------------- 93 * Topology Configuration 94 */ 95 96static const struct dcmipp_ent_config stm32mp13_ent_config[] = { 97 { 98 .name = "dcmipp_parallel", 99 .init = dcmipp_par_ent_init, 100 .release = dcmipp_par_ent_release, 101 }, 102 { 103 .name = "dcmipp_dump_postproc", 104 .init = dcmipp_byteproc_ent_init, 105 .release = dcmipp_byteproc_ent_release, 106 }, 107 { 108 .name = "dcmipp_dump_capture", 109 .init = dcmipp_bytecap_ent_init, 110 .release = dcmipp_bytecap_ent_release, 111 }, 112}; 113 114#define ID_PARALLEL 0 115#define ID_DUMP_BYTEPROC 1 116#define ID_DUMP_CAPTURE 2 117 118static const struct dcmipp_ent_link stm32mp13_ent_links[] = { 119 DCMIPP_ENT_LINK(ID_PARALLEL, 1, ID_DUMP_BYTEPROC, 0, 120 MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 121 DCMIPP_ENT_LINK(ID_DUMP_BYTEPROC, 1, ID_DUMP_CAPTURE, 0, 122 MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 123}; 124 125static const struct dcmipp_pipeline_config stm32mp13_pipe_cfg = { 126 .ents = stm32mp13_ent_config, 127 .num_ents = ARRAY_SIZE(stm32mp13_ent_config), 128 .links = stm32mp13_ent_links, 129 .num_links = ARRAY_SIZE(stm32mp13_ent_links) 130}; 131 132#define LINK_FLAG_TO_STR(f) ((f) == 0 ? "" :\ 133 (f) == MEDIA_LNK_FL_ENABLED ? "ENABLED" :\ 134 (f) == MEDIA_LNK_FL_IMMUTABLE ? "IMMUTABLE" :\ 135 (f) == (MEDIA_LNK_FL_ENABLED |\ 136 MEDIA_LNK_FL_IMMUTABLE) ?\ 137 "ENABLED, IMMUTABLE" :\ 138 "UNKNOWN") 139 140static int dcmipp_create_links(struct dcmipp_device *dcmipp) 141{ 142 unsigned int i; 143 int ret; 144 145 /* Initialize the links between entities */ 146 for (i = 0; i < dcmipp->pipe_cfg->num_links; i++) { 147 const struct dcmipp_ent_link *link = 148 &dcmipp->pipe_cfg->links[i]; 149 struct dcmipp_ent_device *ved_src = 150 dcmipp->entity[link->src_ent]; 151 struct dcmipp_ent_device *ved_sink = 152 dcmipp->entity[link->sink_ent]; 153 154 dev_dbg(dcmipp->dev, "Create link \"%s\":%d -> %d:\"%s\" [%s]\n", 155 dcmipp->pipe_cfg->ents[link->src_ent].name, 156 link->src_pad, link->sink_pad, 157 dcmipp->pipe_cfg->ents[link->sink_ent].name, 158 LINK_FLAG_TO_STR(link->flags)); 159 160 ret = media_create_pad_link(ved_src->ent, link->src_pad, 161 ved_sink->ent, link->sink_pad, 162 link->flags); 163 if (ret) 164 return ret; 165 } 166 167 return 0; 168} 169 170static int dcmipp_graph_init(struct dcmipp_device *dcmipp); 171 172static int dcmipp_create_subdevs(struct dcmipp_device *dcmipp) 173{ 174 int ret, i; 175 176 /* Call all subdev inits */ 177 for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) { 178 const char *name = dcmipp->pipe_cfg->ents[i].name; 179 180 dev_dbg(dcmipp->dev, "add subdev %s\n", name); 181 dcmipp->entity[i] = 182 dcmipp->pipe_cfg->ents[i].init(dcmipp->dev, name, 183 &dcmipp->v4l2_dev, 184 dcmipp->regs); 185 if (IS_ERR(dcmipp->entity[i])) { 186 dev_err(dcmipp->dev, "failed to init subdev %s\n", 187 name); 188 ret = PTR_ERR(dcmipp->entity[i]); 189 goto err_init_entity; 190 } 191 } 192 193 /* Initialize links */ 194 ret = dcmipp_create_links(dcmipp); 195 if (ret) 196 goto err_init_entity; 197 198 ret = dcmipp_graph_init(dcmipp); 199 if (ret < 0) 200 goto err_init_entity; 201 202 return 0; 203 204err_init_entity: 205 while (i > 0) 206 dcmipp->pipe_cfg->ents[i - 1].release(dcmipp->entity[i - 1]); 207 return ret; 208} 209 210static const struct of_device_id dcmipp_of_match[] = { 211 { .compatible = "st,stm32mp13-dcmipp", .data = &stm32mp13_pipe_cfg }, 212 { /* end node */ }, 213}; 214MODULE_DEVICE_TABLE(of, dcmipp_of_match); 215 216static irqreturn_t dcmipp_irq_thread(int irq, void *arg) 217{ 218 struct dcmipp_device *dcmipp = arg; 219 struct dcmipp_ent_device *ved; 220 unsigned int i; 221 222 /* Call irq thread of each entities of pipeline */ 223 for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) { 224 ved = dcmipp->entity[i]; 225 if (ved->thread_fn && ved->handler_ret == IRQ_WAKE_THREAD) 226 ved->thread_fn(irq, ved); 227 } 228 229 return IRQ_HANDLED; 230} 231 232static irqreturn_t dcmipp_irq_callback(int irq, void *arg) 233{ 234 struct dcmipp_device *dcmipp = arg; 235 struct dcmipp_ent_device *ved; 236 irqreturn_t ret = IRQ_HANDLED; 237 unsigned int i; 238 239 /* Call irq handler of each entities of pipeline */ 240 for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) { 241 ved = dcmipp->entity[i]; 242 if (ved->handler) 243 ved->handler_ret = ved->handler(irq, ved); 244 else if (ved->thread_fn) 245 ved->handler_ret = IRQ_WAKE_THREAD; 246 else 247 ved->handler_ret = IRQ_HANDLED; 248 if (ved->handler_ret != IRQ_HANDLED) 249 ret = ved->handler_ret; 250 } 251 252 return ret; 253} 254 255static int dcmipp_graph_notify_bound(struct v4l2_async_notifier *notifier, 256 struct v4l2_subdev *subdev, 257 struct v4l2_async_connection *asd) 258{ 259 struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier); 260 unsigned int ret; 261 int src_pad; 262 struct dcmipp_ent_device *sink; 263 struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_PARALLEL }; 264 struct fwnode_handle *ep; 265 266 dev_dbg(dcmipp->dev, "Subdev \"%s\" bound\n", subdev->name); 267 268 /* 269 * Link this sub-device to DCMIPP, it could be 270 * a parallel camera sensor or a CSI-2 to parallel bridge 271 */ 272 src_pad = media_entity_get_fwnode_pad(&subdev->entity, 273 subdev->fwnode, 274 MEDIA_PAD_FL_SOURCE); 275 276 /* Get bus characteristics from devicetree */ 277 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0, 278 FWNODE_GRAPH_ENDPOINT_NEXT); 279 if (!ep) { 280 dev_err(dcmipp->dev, "Could not find the endpoint\n"); 281 return -ENODEV; 282 } 283 284 /* Check for parallel bus-type first, then bt656 */ 285 ret = v4l2_fwnode_endpoint_parse(ep, &vep); 286 if (ret) { 287 vep.bus_type = V4L2_MBUS_BT656; 288 ret = v4l2_fwnode_endpoint_parse(ep, &vep); 289 if (ret) { 290 dev_err(dcmipp->dev, "Could not parse the endpoint\n"); 291 fwnode_handle_put(ep); 292 return ret; 293 } 294 } 295 296 fwnode_handle_put(ep); 297 298 if (vep.bus.parallel.bus_width == 0) { 299 dev_err(dcmipp->dev, "Invalid parallel interface bus-width\n"); 300 return -ENODEV; 301 } 302 303 /* Only 8 bits bus width supported with BT656 bus */ 304 if (vep.bus_type == V4L2_MBUS_BT656 && 305 vep.bus.parallel.bus_width != 8) { 306 dev_err(dcmipp->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n", 307 vep.bus.parallel.bus_width); 308 return -ENODEV; 309 } 310 311 /* Parallel input device detected, connect it to parallel subdev */ 312 sink = dcmipp->entity[ID_PARALLEL]; 313 sink->bus.flags = vep.bus.parallel.flags; 314 sink->bus.bus_width = vep.bus.parallel.bus_width; 315 sink->bus.data_shift = vep.bus.parallel.data_shift; 316 sink->bus_type = vep.bus_type; 317 ret = media_create_pad_link(&subdev->entity, src_pad, sink->ent, 0, 318 MEDIA_LNK_FL_IMMUTABLE | 319 MEDIA_LNK_FL_ENABLED); 320 if (ret) { 321 dev_err(dcmipp->dev, "Failed to create media pad link with subdev \"%s\"\n", 322 subdev->name); 323 return ret; 324 } 325 326 dev_dbg(dcmipp->dev, "DCMIPP is now linked to \"%s\"\n", subdev->name); 327 328 return 0; 329} 330 331static void dcmipp_graph_notify_unbind(struct v4l2_async_notifier *notifier, 332 struct v4l2_subdev *sd, 333 struct v4l2_async_connection *asd) 334{ 335 struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier); 336 337 dev_dbg(dcmipp->dev, "Removing %s\n", sd->name); 338} 339 340static int dcmipp_graph_notify_complete(struct v4l2_async_notifier *notifier) 341{ 342 struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier); 343 int ret; 344 345 /* Register the media device */ 346 ret = media_device_register(&dcmipp->mdev); 347 if (ret) { 348 dev_err(dcmipp->mdev.dev, 349 "media device register failed (err=%d)\n", ret); 350 return ret; 351 } 352 353 /* Expose all subdev's nodes*/ 354 ret = v4l2_device_register_subdev_nodes(&dcmipp->v4l2_dev); 355 if (ret) { 356 dev_err(dcmipp->mdev.dev, 357 "dcmipp subdev nodes registration failed (err=%d)\n", 358 ret); 359 media_device_unregister(&dcmipp->mdev); 360 return ret; 361 } 362 363 dev_dbg(dcmipp->dev, "Notify complete !\n"); 364 365 return 0; 366} 367 368static const struct v4l2_async_notifier_operations dcmipp_graph_notify_ops = { 369 .bound = dcmipp_graph_notify_bound, 370 .unbind = dcmipp_graph_notify_unbind, 371 .complete = dcmipp_graph_notify_complete, 372}; 373 374static int dcmipp_graph_init(struct dcmipp_device *dcmipp) 375{ 376 struct v4l2_async_connection *asd; 377 struct fwnode_handle *ep; 378 int ret; 379 380 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0, 381 FWNODE_GRAPH_ENDPOINT_NEXT); 382 if (!ep) { 383 dev_err(dcmipp->dev, "Failed to get next endpoint\n"); 384 return -EINVAL; 385 } 386 387 v4l2_async_nf_init(&dcmipp->notifier, &dcmipp->v4l2_dev); 388 389 asd = v4l2_async_nf_add_fwnode_remote(&dcmipp->notifier, ep, 390 struct v4l2_async_connection); 391 392 fwnode_handle_put(ep); 393 394 if (IS_ERR(asd)) { 395 dev_err(dcmipp->dev, "Failed to add fwnode remote subdev\n"); 396 return PTR_ERR(asd); 397 } 398 399 dcmipp->notifier.ops = &dcmipp_graph_notify_ops; 400 401 ret = v4l2_async_nf_register(&dcmipp->notifier); 402 if (ret < 0) { 403 dev_err(dcmipp->dev, "Failed to register notifier\n"); 404 v4l2_async_nf_cleanup(&dcmipp->notifier); 405 return ret; 406 } 407 408 return 0; 409} 410 411static int dcmipp_probe(struct platform_device *pdev) 412{ 413 struct dcmipp_device *dcmipp; 414 struct clk *kclk; 415 const struct dcmipp_pipeline_config *pipe_cfg; 416 struct reset_control *rstc; 417 int irq; 418 int ret; 419 420 dcmipp = devm_kzalloc(&pdev->dev, sizeof(*dcmipp), GFP_KERNEL); 421 if (!dcmipp) 422 return -ENOMEM; 423 424 dcmipp->dev = &pdev->dev; 425 426 pipe_cfg = device_get_match_data(dcmipp->dev); 427 if (!pipe_cfg) { 428 dev_err(&pdev->dev, "Can't get device data\n"); 429 return -ENODEV; 430 } 431 dcmipp->pipe_cfg = pipe_cfg; 432 433 platform_set_drvdata(pdev, dcmipp); 434 435 /* Get hardware resources from devicetree */ 436 rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); 437 if (IS_ERR(rstc)) 438 return dev_err_probe(&pdev->dev, PTR_ERR(rstc), 439 "Could not get reset control\n"); 440 441 irq = platform_get_irq(pdev, 0); 442 if (irq <= 0) { 443 if (irq != -EPROBE_DEFER) 444 dev_err(&pdev->dev, "Could not get irq\n"); 445 return irq ? irq : -ENXIO; 446 } 447 448 dcmipp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 449 if (IS_ERR(dcmipp->regs)) { 450 dev_err(&pdev->dev, "Could not map registers\n"); 451 return PTR_ERR(dcmipp->regs); 452 } 453 454 ret = devm_request_threaded_irq(&pdev->dev, irq, dcmipp_irq_callback, 455 dcmipp_irq_thread, IRQF_ONESHOT, 456 dev_name(&pdev->dev), dcmipp); 457 if (ret) { 458 dev_err(&pdev->dev, "Unable to request irq %d\n", irq); 459 return ret; 460 } 461 462 /* Reset device */ 463 ret = reset_control_assert(rstc); 464 if (ret) { 465 dev_err(&pdev->dev, "Failed to assert the reset line\n"); 466 return ret; 467 } 468 469 usleep_range(3000, 5000); 470 471 ret = reset_control_deassert(rstc); 472 if (ret) { 473 dev_err(&pdev->dev, "Failed to deassert the reset line\n"); 474 return ret; 475 } 476 477 kclk = devm_clk_get(&pdev->dev, NULL); 478 if (IS_ERR(kclk)) 479 return dev_err_probe(&pdev->dev, PTR_ERR(kclk), 480 "Unable to get kclk\n"); 481 dcmipp->kclk = kclk; 482 483 dcmipp->entity = devm_kcalloc(&pdev->dev, dcmipp->pipe_cfg->num_ents, 484 sizeof(*dcmipp->entity), GFP_KERNEL); 485 if (!dcmipp->entity) 486 return -ENOMEM; 487 488 /* Register the v4l2 struct */ 489 ret = v4l2_device_register(&pdev->dev, &dcmipp->v4l2_dev); 490 if (ret) { 491 dev_err(&pdev->dev, 492 "v4l2 device register failed (err=%d)\n", ret); 493 return ret; 494 } 495 496 /* Link the media device within the v4l2_device */ 497 dcmipp->v4l2_dev.mdev = &dcmipp->mdev; 498 499 /* Initialize media device */ 500 strscpy(dcmipp->mdev.model, DCMIPP_MDEV_MODEL_NAME, 501 sizeof(dcmipp->mdev.model)); 502 dcmipp->mdev.dev = &pdev->dev; 503 media_device_init(&dcmipp->mdev); 504 505 /* Initialize subdevs */ 506 ret = dcmipp_create_subdevs(dcmipp); 507 if (ret) { 508 media_device_cleanup(&dcmipp->mdev); 509 v4l2_device_unregister(&dcmipp->v4l2_dev); 510 return ret; 511 } 512 513 pm_runtime_enable(dcmipp->dev); 514 515 dev_info(&pdev->dev, "Probe done"); 516 517 return 0; 518} 519 520static void dcmipp_remove(struct platform_device *pdev) 521{ 522 struct dcmipp_device *dcmipp = platform_get_drvdata(pdev); 523 unsigned int i; 524 525 pm_runtime_disable(&pdev->dev); 526 527 v4l2_async_nf_unregister(&dcmipp->notifier); 528 v4l2_async_nf_cleanup(&dcmipp->notifier); 529 530 for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) 531 dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]); 532 533 media_device_unregister(&dcmipp->mdev); 534 media_device_cleanup(&dcmipp->mdev); 535 536 v4l2_device_unregister(&dcmipp->v4l2_dev); 537} 538 539static int dcmipp_runtime_suspend(struct device *dev) 540{ 541 struct dcmipp_device *dcmipp = dev_get_drvdata(dev); 542 543 clk_disable_unprepare(dcmipp->kclk); 544 545 return 0; 546} 547 548static int dcmipp_runtime_resume(struct device *dev) 549{ 550 struct dcmipp_device *dcmipp = dev_get_drvdata(dev); 551 int ret; 552 553 ret = clk_prepare_enable(dcmipp->kclk); 554 if (ret) 555 dev_err(dev, "%s: Failed to prepare_enable kclk\n", __func__); 556 557 return ret; 558} 559 560static int dcmipp_suspend(struct device *dev) 561{ 562 /* disable clock */ 563 pm_runtime_force_suspend(dev); 564 565 /* change pinctrl state */ 566 pinctrl_pm_select_sleep_state(dev); 567 568 return 0; 569} 570 571static int dcmipp_resume(struct device *dev) 572{ 573 /* restore pinctl default state */ 574 pinctrl_pm_select_default_state(dev); 575 576 /* clock enable */ 577 pm_runtime_force_resume(dev); 578 579 return 0; 580} 581 582static const struct dev_pm_ops dcmipp_pm_ops = { 583 SYSTEM_SLEEP_PM_OPS(dcmipp_suspend, dcmipp_resume) 584 RUNTIME_PM_OPS(dcmipp_runtime_suspend, dcmipp_runtime_resume, NULL) 585}; 586 587static struct platform_driver dcmipp_pdrv = { 588 .probe = dcmipp_probe, 589 .remove_new = dcmipp_remove, 590 .driver = { 591 .name = DCMIPP_PDEV_NAME, 592 .of_match_table = dcmipp_of_match, 593 .pm = pm_ptr(&dcmipp_pm_ops), 594 }, 595}; 596 597module_platform_driver(dcmipp_pdrv); 598 599MODULE_AUTHOR("Hugues Fruchet <hugues.fruchet@foss.st.com>"); 600MODULE_AUTHOR("Alain Volmat <alain.volmat@foss.st.com>"); 601MODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface with Pixel Processor driver"); 602MODULE_LICENSE("GPL"); 603