Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: stm32: dcmipp: add core support for the stm32mp25

The stm32mp25 supports both parallel & csi inputs.
An additional clock control is necessary.
Skeleton of the subdev structures for the stm32mp25 is added,
identical for the time being to the stm32mp13 however more subdeves
will be added in further commits.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>

authored by

Alain Volmat and committed by
Hans Verkuil
686f27f7 923b428c

+85 -19
+85 -19
drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
··· 40 40 41 41 /* Hardware resources */ 42 42 void __iomem *regs; 43 + struct clk *mclk; 43 44 struct clk *kclk; 44 45 45 46 /* The pipeline configuration */ ··· 133 132 .hw_revision = DCMIPP_STM32MP13_VERR 134 133 }; 135 134 135 + static const struct dcmipp_ent_config stm32mp25_ent_config[] = { 136 + { 137 + .name = "dcmipp_input", 138 + .init = dcmipp_inp_ent_init, 139 + .release = dcmipp_inp_ent_release, 140 + }, 141 + { 142 + .name = "dcmipp_dump_postproc", 143 + .init = dcmipp_byteproc_ent_init, 144 + .release = dcmipp_byteproc_ent_release, 145 + }, 146 + { 147 + .name = "dcmipp_dump_capture", 148 + .init = dcmipp_bytecap_ent_init, 149 + .release = dcmipp_bytecap_ent_release, 150 + }, 151 + }; 152 + 153 + static const struct dcmipp_ent_link stm32mp25_ent_links[] = { 154 + DCMIPP_ENT_LINK(ID_INPUT, 1, ID_DUMP_BYTEPROC, 0, 155 + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 156 + DCMIPP_ENT_LINK(ID_DUMP_BYTEPROC, 1, ID_DUMP_CAPTURE, 0, 157 + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 158 + }; 159 + 160 + #define DCMIPP_STM32MP25_VERR 0x30 161 + static const struct dcmipp_pipeline_config stm32mp25_pipe_cfg = { 162 + .ents = stm32mp25_ent_config, 163 + .num_ents = ARRAY_SIZE(stm32mp25_ent_config), 164 + .links = stm32mp25_ent_links, 165 + .num_links = ARRAY_SIZE(stm32mp25_ent_links), 166 + .hw_revision = DCMIPP_STM32MP25_VERR 167 + }; 168 + 136 169 #define LINK_FLAG_TO_STR(f) ((f) == 0 ? "" :\ 137 170 (f) == MEDIA_LNK_FL_ENABLED ? "ENABLED" :\ 138 171 (f) == MEDIA_LNK_FL_IMMUTABLE ? "IMMUTABLE" :\ ··· 247 212 248 213 static const struct of_device_id dcmipp_of_match[] = { 249 214 { .compatible = "st,stm32mp13-dcmipp", .data = &stm32mp13_pipe_cfg }, 215 + { .compatible = "st,stm32mp25-dcmipp", .data = &stm32mp25_pipe_cfg }, 250 216 { /* end node */ }, 251 217 }; 252 218 MODULE_DEVICE_TABLE(of, dcmipp_of_match); ··· 297 261 { 298 262 struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier); 299 263 unsigned int ret; 300 - int src_pad; 264 + int src_pad, i; 301 265 struct dcmipp_ent_device *sink; 302 - struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_PARALLEL }; 266 + struct v4l2_fwnode_endpoint vep = { 0 }; 303 267 struct fwnode_handle *ep; 268 + enum v4l2_mbus_type supported_types[] = { 269 + V4L2_MBUS_PARALLEL, V4L2_MBUS_BT656, V4L2_MBUS_CSI2_DPHY 270 + }; 271 + int supported_types_nb = ARRAY_SIZE(supported_types); 304 272 305 273 dev_dbg(dcmipp->dev, "Subdev \"%s\" bound\n", subdev->name); 274 + 275 + /* Only MP25 supports CSI input */ 276 + if (!of_device_is_compatible(dcmipp->dev->of_node, 277 + "st,stm32mp25-dcmipp")) 278 + supported_types_nb--; 306 279 307 280 /* 308 281 * Link this sub-device to DCMIPP, it could be ··· 329 284 return -ENODEV; 330 285 } 331 286 332 - /* Check for parallel bus-type first, then bt656 */ 333 - ret = v4l2_fwnode_endpoint_parse(ep, &vep); 334 - if (ret) { 335 - vep.bus_type = V4L2_MBUS_BT656; 287 + /* Check for supported MBUS type */ 288 + for (i = 0; i < supported_types_nb; i++) { 289 + vep.bus_type = supported_types[i]; 336 290 ret = v4l2_fwnode_endpoint_parse(ep, &vep); 337 - if (ret) { 338 - dev_err(dcmipp->dev, "Could not parse the endpoint\n"); 339 - fwnode_handle_put(ep); 340 - return ret; 341 - } 291 + if (!ret) 292 + break; 342 293 } 343 294 344 295 fwnode_handle_put(ep); 345 296 346 - if (vep.bus.parallel.bus_width == 0) { 297 + if (ret) { 298 + dev_err(dcmipp->dev, "Could not parse the endpoint\n"); 299 + return ret; 300 + } 301 + 302 + if (vep.bus_type != V4L2_MBUS_CSI2_DPHY && 303 + vep.bus.parallel.bus_width == 0) { 347 304 dev_err(dcmipp->dev, "Invalid parallel interface bus-width\n"); 348 305 return -ENODEV; 349 306 } ··· 358 311 return -ENODEV; 359 312 } 360 313 361 - /* Parallel input device detected, connect it to parallel subdev */ 314 + /* Connect input device to the dcmipp_input subdev */ 362 315 sink = dcmipp->entity[ID_INPUT]; 363 - sink->bus.flags = vep.bus.parallel.flags; 364 - sink->bus.bus_width = vep.bus.parallel.bus_width; 365 - sink->bus.data_shift = vep.bus.parallel.data_shift; 316 + if (vep.bus_type != V4L2_MBUS_CSI2_DPHY) { 317 + sink->bus.flags = vep.bus.parallel.flags; 318 + sink->bus.bus_width = vep.bus.parallel.bus_width; 319 + sink->bus.data_shift = vep.bus.parallel.data_shift; 320 + } 366 321 sink->bus_type = vep.bus_type; 367 322 ret = media_create_pad_link(&subdev->entity, src_pad, sink->ent, 0, 368 323 MEDIA_LNK_FL_IMMUTABLE | ··· 463 414 static int dcmipp_probe(struct platform_device *pdev) 464 415 { 465 416 struct dcmipp_device *dcmipp; 466 - struct clk *kclk; 417 + struct clk *kclk, *mclk; 467 418 const struct dcmipp_pipeline_config *pipe_cfg; 468 419 struct reset_control *rstc; 469 420 int irq; ··· 523 474 return ret; 524 475 } 525 476 526 - kclk = devm_clk_get(&pdev->dev, NULL); 477 + kclk = devm_clk_get(&pdev->dev, "kclk"); 527 478 if (IS_ERR(kclk)) 528 479 return dev_err_probe(&pdev->dev, PTR_ERR(kclk), 529 480 "Unable to get kclk\n"); 530 481 dcmipp->kclk = kclk; 482 + 483 + if (!of_device_is_compatible(pdev->dev.of_node, "st,stm32mp13-dcmipp")) { 484 + mclk = devm_clk_get(&pdev->dev, "mclk"); 485 + if (IS_ERR(mclk)) 486 + return dev_err_probe(&pdev->dev, PTR_ERR(mclk), 487 + "Unable to get mclk\n"); 488 + dcmipp->mclk = mclk; 489 + } 531 490 532 491 dcmipp->entity = devm_kcalloc(&pdev->dev, dcmipp->pipe_cfg->num_ents, 533 492 sizeof(*dcmipp->entity), GFP_KERNEL); ··· 599 542 struct dcmipp_device *dcmipp = dev_get_drvdata(dev); 600 543 601 544 clk_disable_unprepare(dcmipp->kclk); 545 + clk_disable_unprepare(dcmipp->mclk); 602 546 603 547 return 0; 604 548 } ··· 609 551 struct dcmipp_device *dcmipp = dev_get_drvdata(dev); 610 552 int ret; 611 553 554 + ret = clk_prepare_enable(dcmipp->mclk); 555 + if (ret) { 556 + dev_err(dev, "%s: Failed to prepare_enable mclk\n", __func__); 557 + return ret; 558 + } 559 + 612 560 ret = clk_prepare_enable(dcmipp->kclk); 613 - if (ret) 561 + if (ret) { 562 + clk_disable_unprepare(dcmipp->mclk); 614 563 dev_err(dev, "%s: Failed to prepare_enable kclk\n", __func__); 564 + } 615 565 616 566 return ret; 617 567 }