Lines Matching +full:dphy +full:- +full:cfg

1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Cadence MIPI-CSI2 TX Controller
5 * Copyright (C) 2017-2019 Cadence Design Systems Inc.
18 #include <media/mipi-csi2.h>
19 #include <media/v4l2-ctrls.h>
20 #include <media/v4l2-device.h>
21 #include <media/v4l2-fwnode.h>
22 #include <media/v4l2-subdev.h>
163 if (code->pad || code->index >= ARRAY_SIZE(csi2tx_formats)) in csi2tx_enum_mbus_code()
164 return -EINVAL; in csi2tx_enum_mbus_code()
166 code->code = csi2tx_formats[code->index].mbus; in csi2tx_enum_mbus_code()
178 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) in __csi2tx_get_pad_format()
179 return v4l2_subdev_state_get_format(sd_state, fmt->pad); in __csi2tx_get_pad_format()
181 return &csi2tx->pad_fmts[fmt->pad]; in __csi2tx_get_pad_format()
191 if (fmt->pad == CSI2TX_PAD_SOURCE) in csi2tx_get_pad_format()
192 return -EINVAL; in csi2tx_get_pad_format()
196 return -EINVAL; in csi2tx_get_pad_format()
198 fmt->format = *format; in csi2tx_get_pad_format()
207 const struct v4l2_mbus_framefmt *src_format = &fmt->format; in csi2tx_set_pad_format()
211 if (fmt->pad == CSI2TX_PAD_SOURCE) in csi2tx_set_pad_format()
212 return -EINVAL; in csi2tx_set_pad_format()
214 if (!csi2tx_get_fmt_from_mbus(fmt->format.code)) in csi2tx_set_pad_format()
219 return -EINVAL; in csi2tx_set_pad_format()
232 /* Set Wake Up value in the D-PHY */
236 csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG); in csi2tx_dphy_set_wakeup()
240 * Finishes the D-PHY initialization
241 * reg dphy cfg value to be used
251 for (i = 0; i < csi2tx->num_lanes; i++) in csi2tx_dphy_init_finish()
252 reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1); in csi2tx_dphy_init_finish()
253 writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); in csi2tx_dphy_init_finish()
260 csi2tx->base + CSI2TX_DPHY_CFG_REG); in csi2tx_dphy_init_finish()
263 /* Configures D-PHY in CSIv1.3 */
273 for (i = 0; i < csi2tx->num_lanes; i++) in csi2tx_dphy_setup()
274 reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i] - 1); in csi2tx_dphy_setup()
275 writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG); in csi2tx_dphy_setup()
280 /* Configures D-PHY in CSIv2 */
289 writel(reg, csi2tx->base + CSI2TX_V2_DPHY_CFG_REG); in csi2tx_v2_dphy_setup()
296 writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG); in csi2tx_reset()
303 struct media_entity *entity = &csi2tx->subdev.entity; in csi2tx_start()
309 writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG); in csi2tx_start()
313 if (csi2tx->vops && csi2tx->vops->dphy_setup) { in csi2tx_start()
314 csi2tx->vops->dphy_setup(csi2tx); in csi2tx_start()
329 list_for_each_entry(link, &entity->links, list) { in csi2tx_start()
333 int pad_idx = -1; in csi2tx_start()
337 struct media_pad *pad = &csi2tx->pads[i]; in csi2tx_start()
339 if ((pad == link->sink) && in csi2tx_start()
340 (link->flags & MEDIA_LNK_FL_ENABLED)) { in csi2tx_start()
349 mfmt = &csi2tx->pad_fmts[pad_idx]; in csi2tx_start()
350 fmt = csi2tx_get_fmt_from_mbus(mfmt->code); in csi2tx_start()
354 stream = pad_idx - CSI2TX_PAD_SINK_STREAM0; in csi2tx_start()
363 writel(CSI2TX_DT_CFG_DT(fmt->dt), in csi2tx_start()
364 csi2tx->base + CSI2TX_DT_CFG_REG(stream)); in csi2tx_start()
366 writel(CSI2TX_DT_FORMAT_BYTES_PER_LINE(mfmt->width * fmt->bpp) | in csi2tx_start()
367 CSI2TX_DT_FORMAT_MAX_LINE_NUM(mfmt->height + 1), in csi2tx_start()
368 csi2tx->base + CSI2TX_DT_FORMAT_REG(stream)); in csi2tx_start()
375 csi2tx->base + CSI2TX_STREAM_IF_CFG_REG(stream)); in csi2tx_start()
379 writel(0, csi2tx->base + CSI2TX_CONFIG_REG); in csi2tx_start()
387 csi2tx->base + CSI2TX_CONFIG_REG); in csi2tx_stop()
395 mutex_lock(&csi2tx->lock); in csi2tx_s_stream()
402 if (!csi2tx->count) { in csi2tx_s_stream()
408 csi2tx->count++; in csi2tx_s_stream()
410 csi2tx->count--; in csi2tx_s_stream()
415 if (!csi2tx->count) in csi2tx_s_stream()
420 mutex_unlock(&csi2tx->lock); in csi2tx_s_stream()
440 csi2tx->base = devm_platform_ioremap_resource(pdev, 0); in csi2tx_get_resources()
441 if (IS_ERR(csi2tx->base)) in csi2tx_get_resources()
442 return PTR_ERR(csi2tx->base); in csi2tx_get_resources()
444 csi2tx->p_clk = devm_clk_get(&pdev->dev, "p_clk"); in csi2tx_get_resources()
445 if (IS_ERR(csi2tx->p_clk)) { in csi2tx_get_resources()
446 dev_err(&pdev->dev, "Couldn't get p_clk\n"); in csi2tx_get_resources()
447 return PTR_ERR(csi2tx->p_clk); in csi2tx_get_resources()
450 csi2tx->esc_clk = devm_clk_get(&pdev->dev, "esc_clk"); in csi2tx_get_resources()
451 if (IS_ERR(csi2tx->esc_clk)) { in csi2tx_get_resources()
452 dev_err(&pdev->dev, "Couldn't get the esc_clk\n"); in csi2tx_get_resources()
453 return PTR_ERR(csi2tx->esc_clk); in csi2tx_get_resources()
456 ret = clk_prepare_enable(csi2tx->p_clk); in csi2tx_get_resources()
458 dev_err(&pdev->dev, "Couldn't prepare and enable p_clk\n"); in csi2tx_get_resources()
462 dev_cfg = readl(csi2tx->base + CSI2TX_DEVICE_CONFIG_REG); in csi2tx_get_resources()
463 clk_disable_unprepare(csi2tx->p_clk); in csi2tx_get_resources()
465 csi2tx->max_lanes = dev_cfg & CSI2TX_DEVICE_CONFIG_LANES_MASK; in csi2tx_get_resources()
466 if (csi2tx->max_lanes > CSI2TX_LANES_MAX) { in csi2tx_get_resources()
467 dev_err(&pdev->dev, "Invalid number of lanes: %u\n", in csi2tx_get_resources()
468 csi2tx->max_lanes); in csi2tx_get_resources()
469 return -EINVAL; in csi2tx_get_resources()
472 csi2tx->max_streams = (dev_cfg & CSI2TX_DEVICE_CONFIG_STREAMS_MASK) >> 4; in csi2tx_get_resources()
473 if (csi2tx->max_streams > CSI2TX_STREAMS_MAX) { in csi2tx_get_resources()
474 dev_err(&pdev->dev, "Invalid number of streams: %u\n", in csi2tx_get_resources()
475 csi2tx->max_streams); in csi2tx_get_resources()
476 return -EINVAL; in csi2tx_get_resources()
479 csi2tx->has_internal_dphy = !!(dev_cfg & CSI2TX_DEVICE_CONFIG_HAS_DPHY); in csi2tx_get_resources()
481 for (i = 0; i < csi2tx->max_streams; i++) { in csi2tx_get_resources()
485 csi2tx->pixel_clk[i] = devm_clk_get(&pdev->dev, clk_name); in csi2tx_get_resources()
486 if (IS_ERR(csi2tx->pixel_clk[i])) { in csi2tx_get_resources()
487 dev_err(&pdev->dev, "Couldn't get clock %s\n", in csi2tx_get_resources()
489 return PTR_ERR(csi2tx->pixel_clk[i]); in csi2tx_get_resources()
502 ep = of_graph_get_endpoint_by_regs(csi2tx->dev->of_node, 0, 0); in csi2tx_check_lanes()
504 return -EINVAL; in csi2tx_check_lanes()
508 dev_err(csi2tx->dev, "Could not parse v4l2 endpoint\n"); in csi2tx_check_lanes()
513 dev_err(csi2tx->dev, "Unsupported media bus type: 0x%x\n", in csi2tx_check_lanes()
515 ret = -EINVAL; in csi2tx_check_lanes()
519 csi2tx->num_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; in csi2tx_check_lanes()
520 if (csi2tx->num_lanes > csi2tx->max_lanes) { in csi2tx_check_lanes()
521 dev_err(csi2tx->dev, in csi2tx_check_lanes()
523 ret = -EINVAL; in csi2tx_check_lanes()
527 for (i = 0; i < csi2tx->num_lanes; i++) { in csi2tx_check_lanes()
529 dev_err(csi2tx->dev, "Invalid lane[%d] number: %u\n", in csi2tx_check_lanes()
531 ret = -EINVAL; in csi2tx_check_lanes()
536 memcpy(csi2tx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes, in csi2tx_check_lanes()
537 sizeof(csi2tx->lanes)); in csi2tx_check_lanes()
558 .compatible = "cdns,csi2tx-1.3",
562 .compatible = "cdns,csi2tx-2.1",
578 return -ENOMEM; in csi2tx_probe()
580 mutex_init(&csi2tx->lock); in csi2tx_probe()
581 csi2tx->dev = &pdev->dev; in csi2tx_probe()
587 of_id = of_match_node(csi2tx_of_table, pdev->dev.of_node); in csi2tx_probe()
588 csi2tx->vops = (struct csi2tx_vops *)of_id->data; in csi2tx_probe()
590 v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops); in csi2tx_probe()
591 csi2tx->subdev.owner = THIS_MODULE; in csi2tx_probe()
592 csi2tx->subdev.dev = &pdev->dev; in csi2tx_probe()
593 csi2tx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in csi2tx_probe()
594 snprintf(csi2tx->subdev.name, sizeof(csi2tx->subdev.name), in csi2tx_probe()
595 "%s.%s", KBUILD_MODNAME, dev_name(&pdev->dev)); in csi2tx_probe()
602 csi2tx->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; in csi2tx_probe()
603 csi2tx->pads[CSI2TX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; in csi2tx_probe()
605 csi2tx->pads[i].flags = MEDIA_PAD_FL_SINK; in csi2tx_probe()
614 csi2tx->pad_fmts[i] = fmt_default; in csi2tx_probe()
616 ret = media_entity_pads_init(&csi2tx->subdev.entity, CSI2TX_PAD_MAX, in csi2tx_probe()
617 csi2tx->pads); in csi2tx_probe()
621 ret = v4l2_async_register_subdev(&csi2tx->subdev); in csi2tx_probe()
625 dev_info(&pdev->dev, in csi2tx_probe()
626 "Probed CSI2TX with %u/%u lanes, %u streams, %s D-PHY\n", in csi2tx_probe()
627 csi2tx->num_lanes, csi2tx->max_lanes, csi2tx->max_streams, in csi2tx_probe()
628 csi2tx->has_internal_dphy ? "internal" : "no"); in csi2tx_probe()
641 v4l2_async_unregister_subdev(&csi2tx->subdev); in csi2tx_remove()
650 .name = "cdns-csi2tx",
656 MODULE_DESCRIPTION("Cadence CSI2-TX controller");