Lines Matching +full:stm32mp25 +full:- +full:csi

1 // SPDX-License-Identifier: GPL-2.0
20 #include <media/mipi-csi2.h>
21 #include <media/v4l2-fwnode.h>
22 #include <media/v4l2-subdev.h>
143 {STM32_CSI_SR1_ECTRLDL1F, "L1: D-PHY control error"},
145 "L1: D-PHY low power data transmission synchro error"},
146 {STM32_CSI_SR1_EESCDL1F, "L1: D-PHY escape entry error"},
150 {STM32_CSI_SR1_ECTRLDL0F, "L0: D-PHY control error"},
152 "L0: D-PHY low power data transmission synchro error"},
153 {STM32_CSI_SR1_EESCDL0F, "L0: D-PHY escape entry error"},
261 * intended Bit Rate. From table 5-8 Frequency Ranges and Defaults
363 for (i = 0; i < csidev->num_lanes; i++) { in stm32_csi_setup_lane_merger()
364 if (!csidev->lanes[i] || csidev->lanes[i] > STM32_CSI_LANES_MAX) { in stm32_csi_setup_lane_merger()
365 dev_err(csidev->dev, "Invalid lane id (%d)\n", csidev->lanes[i]); in stm32_csi_setup_lane_merger()
366 return -EINVAL; in stm32_csi_setup_lane_merger()
368 lmcfgr |= (csidev->lanes[i] << ((i * 4) + STM32_CSI_LMCFGR_DLMAP_SHIFT)); in stm32_csi_setup_lane_merger()
371 lmcfgr |= (csidev->num_lanes << STM32_CSI_LMCFGR_LANENB_SHIFT); in stm32_csi_setup_lane_merger()
373 writel_relaxed(lmcfgr, csidev->base + STM32_CSI_LMCFGR); in stm32_csi_setup_lane_merger()
382 /* For writing the 4-bit testcode MSBs */ in stm32_csi_phy_reg_write()
384 writel_relaxed(STM32_CSI_PTCR1_TWM, csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
387 writel_relaxed(STM32_CSI_PTCR0_TCKEN, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
390 writel_relaxed(STM32_CSI_PTCR1_TWM, csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
396 writel_relaxed(0, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
399 writel_relaxed(0, csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
401 /* Place the 8-bit word corresponding to the testcode MSBs in testdin */ in stm32_csi_phy_reg_write()
403 csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
406 writel_relaxed(STM32_CSI_PTCR0_TCKEN, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
408 /* For writing the 8-bit testcode LSBs */ in stm32_csi_phy_reg_write()
410 writel_relaxed(0, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
413 writel_relaxed(STM32_CSI_PTCR1_TWM, csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
416 writel_relaxed(STM32_CSI_PTCR0_TCKEN, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
418 /* Place the 8-bit word test data in testdin */ in stm32_csi_phy_reg_write()
421 csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
427 writel_relaxed(0, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
430 writel_relaxed(0, csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
433 /* Place the 8-bit word corresponding to the page offset in testdin */ in stm32_csi_phy_reg_write()
435 csidev->base + STM32_CSI_PTCR1); in stm32_csi_phy_reg_write()
438 writel_relaxed(STM32_CSI_PTCR0_TCKEN, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
441 writel_relaxed(0, csidev->base + STM32_CSI_PTCR0); in stm32_csi_phy_reg_write()
458 dev_dbg(csidev->dev, "Starting the CSI2\n"); in stm32_csi_start()
460 /* Get the bpp value on pad0 (input of CSI) */ in stm32_csi_start()
462 fmt = stm32_csi_code_to_fmt(sink_fmt->code); in stm32_csi_start()
465 if (!csidev->s_subdev) in stm32_csi_start()
466 return -EIO; in stm32_csi_start()
468 link_freq = v4l2_get_link_freq(csidev->s_subdev->ctrl_handler, in stm32_csi_start()
469 fmt->bpp, 2 * csidev->num_lanes); in stm32_csi_start()
475 dev_dbg(csidev->dev, "Computed Mbps: %u\n", mbps); in stm32_csi_start()
477 for (phy_regs = snps_stm32mp25; phy_regs->mbps != 0; phy_regs++) in stm32_csi_start()
478 if (phy_regs->mbps >= mbps) in stm32_csi_start()
481 if (!phy_regs->mbps) { in stm32_csi_start()
482 dev_err(csidev->dev, "Unsupported PHY speed (%u Mbps)", mbps); in stm32_csi_start()
483 return -ERANGE; in stm32_csi_start()
486 dev_dbg(csidev->dev, "PHY settings: (%u Mbps, %u HS FRange, %u OSC Freq)\n", in stm32_csi_start()
487 phy_regs->mbps, phy_regs->hsfreqrange, in stm32_csi_start()
488 phy_regs->osc_freq_target); in stm32_csi_start()
493 if (csidev->num_lanes == 2) { in stm32_csi_start()
498 ret = pm_runtime_get_sync(csidev->dev); in stm32_csi_start()
503 phy_clk_frate = clk_get_rate(csidev->clks[STM32_CSI_CLK_CSI2PHY].clk); in stm32_csi_start()
505 pm_runtime_put(csidev->dev); in stm32_csi_start()
506 dev_err(csidev->dev, "CSI2PHY clock rate invalid (0)\n"); in stm32_csi_start()
512 pm_runtime_put(csidev->dev); in stm32_csi_start()
516 /* Enable the CSI */ in stm32_csi_start()
517 writel_relaxed(STM32_CSI_CR_CSIEN, csidev->base + STM32_CSI_CR); in stm32_csi_start()
519 /* Enable some global CSI related interrupts - bits are same as SR0 */ in stm32_csi_start()
520 writel_relaxed(STM32_CSI_SR0_ERRORS, csidev->base + STM32_CSI_IER0); in stm32_csi_start()
523 writel_relaxed(lanes_ie, csidev->base + STM32_CSI_IER1); in stm32_csi_start()
525 /* Initialization of the D-PHY */ in stm32_csi_start()
526 /* Stop the D-PHY */ in stm32_csi_start()
527 writel_relaxed(0, csidev->base + STM32_CSI_PRCR); in stm32_csi_start()
529 /* Keep the D-PHY in power down state */ in stm32_csi_start()
530 writel_relaxed(0, csidev->base + STM32_CSI_PCR); in stm32_csi_start()
533 writel_relaxed(STM32_CSI_PTCR0_TCKEN, csidev->base + STM32_CSI_PTCR0); in stm32_csi_start()
535 writel_relaxed(0, csidev->base + STM32_CSI_PTCR0); in stm32_csi_start()
539 ccfr = (phy_clk_frate - 17) * 4; in stm32_csi_start()
541 (phy_regs->hsfreqrange << STM32_CSI_PFCR_HSFR_SHIFT), in stm32_csi_start()
542 csidev->base + STM32_CSI_PFCR); in stm32_csi_start()
553 stm32_csi_phy_reg_write(csidev, 0xe2, phy_regs->osc_freq_target & 0xFF); in stm32_csi_start()
554 stm32_csi_phy_reg_write(csidev, 0xe3, (phy_regs->osc_freq_target >> 8) & 0x0F); in stm32_csi_start()
556 writel_relaxed(STM32_CSI_PFCR_DLD | readl_relaxed(csidev->base + STM32_CSI_PFCR), in stm32_csi_start()
557 csidev->base + STM32_CSI_PFCR); in stm32_csi_start()
560 writel_relaxed(lanes_en | STM32_CSI_PCR_CLEN, csidev->base + STM32_CSI_PCR); in stm32_csi_start()
562 csidev->base + STM32_CSI_PCR); in stm32_csi_start()
564 writel_relaxed(STM32_CSI_PRCR_PEN, csidev->base + STM32_CSI_PRCR); in stm32_csi_start()
567 writel_relaxed(0, csidev->base + STM32_CSI_PMCR); in stm32_csi_start()
574 dev_dbg(csidev->dev, "Stopping the CSI2\n"); in stm32_csi_stop()
576 /* Disable the D-PHY */ in stm32_csi_stop()
577 writel_relaxed(0, csidev->base + STM32_CSI_PCR); in stm32_csi_stop()
580 writel_relaxed(0, csidev->base + STM32_CSI_IER0); in stm32_csi_stop()
581 writel_relaxed(0, csidev->base + STM32_CSI_IER1); in stm32_csi_stop()
583 /* Disable the CSI */ in stm32_csi_stop()
584 writel_relaxed(0, csidev->base + STM32_CSI_CR); in stm32_csi_stop()
586 pm_runtime_put(csidev->dev); in stm32_csi_stop()
599 fmt = stm32_csi_code_to_fmt(mbus_fmt->code); in stm32_csi_start_vc()
602 if (mbus_fmt->code == MEDIA_BUS_FMT_JPEG_1X8) { in stm32_csi_start_vc()
604 cfgr1 |= fmt->input_fmt << STM32_CSI_VCXCFGR1_CDTFT_SHIFT; in stm32_csi_start_vc()
605 dev_dbg(csidev->dev, "VC%d: enable AllDT mode\n", vc); in stm32_csi_start_vc()
607 cfgr1 |= fmt->datatype << STM32_CSI_VCXCFGR1_DT0_SHIFT; in stm32_csi_start_vc()
608 cfgr1 |= fmt->input_fmt << STM32_CSI_VCXCFGR1_DT0FT_SHIFT; in stm32_csi_start_vc()
610 dev_dbg(csidev->dev, "VC%d: enable DT0(0x%x)/DT0FT(0x%x)\n", in stm32_csi_start_vc()
611 vc, fmt->datatype, fmt->input_fmt); in stm32_csi_start_vc()
613 writel_relaxed(cfgr1, csidev->base + STM32_CSI_VCXCFGR1(vc)); in stm32_csi_start_vc()
615 /* Enable processing of the virtual-channel and wait for its status */ in stm32_csi_start_vc()
617 csidev->base + STM32_CSI_CR); in stm32_csi_start_vc()
619 ret = readl_relaxed_poll_timeout(csidev->base + STM32_CSI_SR0, in stm32_csi_start_vc()
624 dev_err(csidev->dev, "failed to start VC(%d)\n", vc); in stm32_csi_start_vc()
638 csidev->base + STM32_CSI_CR); in stm32_csi_stop_vc()
640 ret = readl_relaxed_poll_timeout(csidev->base + STM32_CSI_SR0, in stm32_csi_stop_vc()
645 dev_err(csidev->dev, "failed to stop VC(%d)\n", vc); in stm32_csi_stop_vc()
650 writel_relaxed(0, csidev->base + STM32_CSI_VCXCFGR1(vc)); in stm32_csi_stop_vc()
651 writel_relaxed(0, csidev->base + STM32_CSI_VCXCFGR2(vc)); in stm32_csi_stop_vc()
663 ret = v4l2_subdev_disable_streams(csidev->s_subdev, in stm32_csi_disable_streams()
664 csidev->s_subdev_pad_nb, BIT_ULL(0)); in stm32_csi_disable_streams()
671 dev_err(csidev->dev, "Failed to stop VC0\n"); in stm32_csi_disable_streams()
692 dev_err(csidev->dev, "Failed to start VC0\n"); in stm32_csi_enable_streams()
697 ret = v4l2_subdev_enable_streams(csidev->s_subdev, in stm32_csi_enable_streams()
698 csidev->s_subdev_pad_nb, BIT_ULL(0)); in stm32_csi_enable_streams()
713 for (i = 0; i < sd->entity.num_pads; i++) in stm32_csi_init_state()
723 if (code->index >= ARRAY_SIZE(stm32_csi_formats)) in stm32_csi_enum_mbus_code()
724 return -EINVAL; in stm32_csi_enum_mbus_code()
726 code->code = stm32_csi_formats[code->index].code; in stm32_csi_enum_mbus_code()
738 fmt = stm32_csi_code_to_fmt(format->format.code); in stm32_csi_set_pad_format()
740 dev_dbg(csidev->dev, "Unsupported code %d, use default\n", in stm32_csi_set_pad_format()
741 format->format.code); in stm32_csi_set_pad_format()
742 format->format.code = fmt_default.code; in stm32_csi_set_pad_format()
747 if (format->pad == STM32_CSI_PAD_SOURCE) in stm32_csi_set_pad_format()
748 format->format = *framefmt; in stm32_csi_set_pad_format()
750 *framefmt = format->format; in stm32_csi_set_pad_format()
753 *framefmt = format->format; in stm32_csi_set_pad_format()
764 spin_lock_irqsave(&csidev->slock, flags); in stm32_csi_log_status()
767 if (csidev->sr0_counters[i]) in stm32_csi_log_status()
768 dev_info(csidev->dev, "%s events: %d\n", in stm32_csi_log_status()
770 csidev->sr0_counters[i]); in stm32_csi_log_status()
774 if (csidev->sr1_counters[i]) in stm32_csi_log_status()
775 dev_info(csidev->dev, "%s events: %d\n", in stm32_csi_log_status()
777 csidev->sr1_counters[i]); in stm32_csi_log_status()
780 spin_unlock_irqrestore(&csidev->slock, flags); in stm32_csi_log_status()
815 struct v4l2_subdev *sd = notifier->sd; in stm32_csi_async_bound()
819 remote_pad = media_entity_get_fwnode_pad(&s_subdev->entity, in stm32_csi_async_bound()
820 s_subdev->fwnode, in stm32_csi_async_bound()
823 dev_err(csidev->dev, "Couldn't find output pad for subdev %s\n", in stm32_csi_async_bound()
824 s_subdev->name); in stm32_csi_async_bound()
828 csidev->s_subdev = s_subdev; in stm32_csi_async_bound()
829 csidev->s_subdev_pad_nb = remote_pad; in stm32_csi_async_bound()
831 return media_create_pad_link(&csidev->s_subdev->entity, in stm32_csi_async_bound()
832 remote_pad, &csidev->sd.entity, in stm32_csi_async_bound()
849 sr0 = readl_relaxed(csidev->base + STM32_CSI_SR0); in stm32_csi_irq_thread()
850 sr1 = readl_relaxed(csidev->base + STM32_CSI_SR1); in stm32_csi_irq_thread()
854 csidev->base + STM32_CSI_FCR0); in stm32_csi_irq_thread()
856 csidev->base + STM32_CSI_FCR1); in stm32_csi_irq_thread()
858 spin_lock_irqsave(&csidev->slock, flags); in stm32_csi_irq_thread()
862 csidev->sr0_counters[i]++; in stm32_csi_irq_thread()
866 csidev->sr1_counters[i]++; in stm32_csi_irq_thread()
868 spin_unlock_irqrestore(&csidev->slock, flags); in stm32_csi_irq_thread()
878 csidev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); in stm32_csi_get_resources()
879 if (IS_ERR(csidev->base)) in stm32_csi_get_resources()
880 return dev_err_probe(&pdev->dev, PTR_ERR(csidev->base), in stm32_csi_get_resources()
884 csidev->clks[i].id = stm32_csi_clks_id[i]; in stm32_csi_get_resources()
886 ret = devm_clk_bulk_get(&pdev->dev, STM32_CSI_CLK_NB, in stm32_csi_get_resources()
887 csidev->clks); in stm32_csi_get_resources()
889 return dev_err_probe(&pdev->dev, ret, "Couldn't get clks\n"); in stm32_csi_get_resources()
891 csidev->supplies[0].supply = "vdd"; in stm32_csi_get_resources()
892 csidev->supplies[1].supply = "vdda18"; in stm32_csi_get_resources()
893 ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(csidev->supplies), in stm32_csi_get_resources()
894 csidev->supplies); in stm32_csi_get_resources()
896 return dev_err_probe(&pdev->dev, ret, in stm32_csi_get_resources()
903 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, in stm32_csi_get_resources()
905 dev_name(&pdev->dev), csidev); in stm32_csi_get_resources()
907 return dev_err_probe(&pdev->dev, ret, in stm32_csi_get_resources()
921 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csidev->dev), 0, 0, in stm32_csi_parse_dt()
924 dev_err(csidev->dev, "Could not find the endpoint\n"); in stm32_csi_parse_dt()
925 return -ENODEV; in stm32_csi_parse_dt()
931 dev_err(csidev->dev, "Could not parse v4l2 endpoint\n"); in stm32_csi_parse_dt()
935 csidev->num_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; in stm32_csi_parse_dt()
936 if (csidev->num_lanes > STM32_CSI_LANES_MAX) { in stm32_csi_parse_dt()
937 dev_err(csidev->dev, "Unsupported number of data-lanes: %d\n", in stm32_csi_parse_dt()
938 csidev->num_lanes); in stm32_csi_parse_dt()
939 return -EINVAL; in stm32_csi_parse_dt()
942 memcpy(csidev->lanes, v4l2_ep.bus.mipi_csi2.data_lanes, in stm32_csi_parse_dt()
943 sizeof(csidev->lanes)); in stm32_csi_parse_dt()
945 ep = fwnode_graph_get_next_endpoint(dev_fwnode(csidev->dev), NULL); in stm32_csi_parse_dt()
947 dev_err(csidev->dev, "Failed to get next endpoint\n"); in stm32_csi_parse_dt()
948 return -EINVAL; in stm32_csi_parse_dt()
951 v4l2_async_subdev_nf_init(&csidev->notifier, &csidev->sd); in stm32_csi_parse_dt()
953 asd = v4l2_async_nf_add_fwnode_remote(&csidev->notifier, ep, in stm32_csi_parse_dt()
959 dev_err(csidev->dev, "Failed to add fwnode remote subdev\n"); in stm32_csi_parse_dt()
963 csidev->notifier.ops = &stm32_csi_notifier_ops; in stm32_csi_parse_dt()
965 ret = v4l2_async_nf_register(&csidev->notifier); in stm32_csi_parse_dt()
967 dev_err(csidev->dev, "Failed to register notifier\n"); in stm32_csi_parse_dt()
968 v4l2_async_nf_cleanup(&csidev->notifier); in stm32_csi_parse_dt()
981 csidev = devm_kzalloc(&pdev->dev, sizeof(*csidev), GFP_KERNEL); in stm32_csi_probe()
983 return -ENOMEM; in stm32_csi_probe()
986 csidev->dev = &pdev->dev; in stm32_csi_probe()
988 spin_lock_init(&csidev->slock); in stm32_csi_probe()
998 csidev->sd.owner = THIS_MODULE; in stm32_csi_probe()
999 csidev->sd.dev = &pdev->dev; in stm32_csi_probe()
1000 csidev->sd.internal_ops = &stm32_csi_subdev_internal_ops; in stm32_csi_probe()
1001 v4l2_subdev_init(&csidev->sd, &stm32_csi_subdev_ops); in stm32_csi_probe()
1002 v4l2_set_subdevdata(&csidev->sd, &pdev->dev); in stm32_csi_probe()
1003 snprintf(csidev->sd.name, sizeof(csidev->sd.name), "%s", in stm32_csi_probe()
1004 dev_name(&pdev->dev)); in stm32_csi_probe()
1007 csidev->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; in stm32_csi_probe()
1008 csidev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in stm32_csi_probe()
1009 csidev->pads[STM32_CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK; in stm32_csi_probe()
1010 csidev->pads[STM32_CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; in stm32_csi_probe()
1012 ret = media_entity_pads_init(&csidev->sd.entity, STM32_CSI_PAD_MAX, in stm32_csi_probe()
1013 csidev->pads); in stm32_csi_probe()
1017 ret = v4l2_subdev_init_finalize(&csidev->sd); in stm32_csi_probe()
1021 ret = v4l2_async_register_subdev(&csidev->sd); in stm32_csi_probe()
1026 rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); in stm32_csi_probe()
1028 ret = dev_err_probe(&pdev->dev, PTR_ERR(rstc), in stm32_csi_probe()
1035 ret = dev_err_probe(&pdev->dev, ret, in stm32_csi_probe()
1044 ret = dev_err_probe(&pdev->dev, ret, in stm32_csi_probe()
1049 pm_runtime_enable(&pdev->dev); in stm32_csi_probe()
1051 dev_info(&pdev->dev, in stm32_csi_probe()
1052 "Probed CSI with %u lanes\n", csidev->num_lanes); in stm32_csi_probe()
1057 v4l2_async_nf_cleanup(&csidev->notifier); in stm32_csi_probe()
1066 v4l2_async_unregister_subdev(&csidev->sd); in stm32_csi_remove()
1068 pm_runtime_disable(&pdev->dev); in stm32_csi_remove()
1076 clk_bulk_disable_unprepare(STM32_CSI_CLK_NB, csidev->clks); in stm32_csi_runtime_suspend()
1078 ret = regulator_bulk_disable(ARRAY_SIZE(csidev->supplies), in stm32_csi_runtime_suspend()
1079 csidev->supplies); in stm32_csi_runtime_suspend()
1091 ret = regulator_bulk_enable(ARRAY_SIZE(csidev->supplies), in stm32_csi_runtime_resume()
1092 csidev->supplies); in stm32_csi_runtime_resume()
1096 ret = clk_bulk_prepare_enable(STM32_CSI_CLK_NB, csidev->clks); in stm32_csi_runtime_resume()
1103 ret = regulator_bulk_disable(ARRAY_SIZE(csidev->supplies), csidev->supplies); in stm32_csi_runtime_resume()
1107 dev_err(csidev->dev, "Failed to resume: %d\n", ret); in stm32_csi_runtime_resume()
1113 { .compatible = "st,stm32mp25-csi", },
1125 .name = "stm32-csi",
1136 MODULE_DESCRIPTION("STM32 CSI controller");