diff --git a/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c b/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c index ef69a77b..875d0b80 100644 --- a/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c +++ b/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c @@ -203,7 +203,10 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id, const struct sensor_mode_properties *mode = NULL; unsigned int cil_settletime = 0; + unsigned int cil_clksettletime = 0; + unsigned int lane_polarity = 0; + unsigned int lane_polarities[NVCSI_BRICK_NUM_LANES] = {0}; int vi_port = 0; struct CAPTURE_CONTROL_MSG msg; @@ -219,11 +222,23 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id, if (s_data) { int idx = s_data->mode_prop_idx; - dev_dbg(csi->dev, "cil_settingtime is pulled from device"); + dev_dbg(csi->dev, "from device s_data\n"); if (idx < s_data->sensor_props.num_modes) { mode = &s_data->sensor_props.sensor_modes[idx]; cil_settletime = mode->signal_properties.cil_settletime; lane_polarity = mode->signal_properties.lane_polarity; + cil_clksettletime = mode->signal_properties.cil_clksettletime; + + for (int i = 0; i < NVCSI_BRICK_NUM_LANES; i++) { + /* + * brick_config.lane_polarity[i] is used for the i-th CPHY trio + * e.g. i=0 for POLARITY_SWIZZLE_CPHY0_A + * i=1 for POLARITY_SWIZZLE_CPHY1_A, etc. + */ + dev_dbg(csi->dev, "lane_polarity[%d] = %d\n", + i, mode->signal_properties.lane_polarities[i]); + lane_polarities[i] = mode->signal_properties.lane_polarities[i]; + } } else { dev_dbg(csi->dev, "mode not listed in DT, use default"); cil_settletime = 0; @@ -233,8 +248,7 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id, int err = 0; const char *str = NULL; - dev_dbg(csi->dev, - "cil_settletime is pulled from device of_node"); + dev_dbg(csi->dev, "from device of_node"); err = of_property_read_string(chan->of_node, "cil_settletime", &str); if (!err) { @@ -247,6 +261,18 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id, } /* Reset string pointer for the next property */ str = NULL; + err = of_property_read_string(chan->of_node, "cil_clksettletime", + &str); + if (!err) { + err = kstrtou32(str, 10, &cil_clksettletime); + if (err) { + dev_dbg(csi->dev, + "no cil_clksettletime in of_node"); + cil_clksettletime = 0; + } + } + /* Reset string pointer for the next property */ + str = NULL; err = of_property_read_string(chan->of_node, "lane_polarity", &str); if (!err) { @@ -269,6 +295,23 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id, unsigned int index = 0; for (index = 0; index < NVCSI_BRICK_NUM_LANES; index++) brick_config.lane_polarity[index] = (lane_polarity >> index) & (0x1); + } else { + /* + * CPHY lane polarity handling: + * brick_config.lane_polarity[0]: + * NVCSI_PHY_0_NVCSI_CIL_A_POLARITY_SWIZZLE_CTRL_0 POLARITY_SWIZZLE_CPHY0_A, + * brick_config.lane_polarity[1]: + * NVCSI_PHY_0_NVCSI_CIL_A_POLARITY_SWIZZLE_CTRL_0 POLARITY_SWIZZLE_CPHY1_A, + * brick_config.lane_polarity[2]: + * NVCSI_PHY_0_NVCSI_CIL_B_POLARITY_SWIZZLE_CTRL_0 POLARITY_SWIZZLE_CPHY0_B, + * brick_config.lane_polarity[3]: + * NVCSI_PHY_0_NVCSI_CIL_B_POLARITY_SWIZZLE_CTRL_0 POLARITY_SWIZZLE_CPHY1_B. + */ + for (int i = 0; i < NVCSI_BRICK_NUM_LANES; i++) { + brick_config.lane_polarity[i] = lane_polarities[i] & 0x7; + dev_dbg(csi->dev, "lane_polarity[%d] = %d\n", + i, brick_config.lane_polarity[i]); + } } /* CIL config */ @@ -276,12 +319,23 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id, cil_config.num_lanes = csi_lanes; cil_config.lp_bypass_mode = is_cphy ? 0 : 1; cil_config.t_hs_settle = cil_settletime; + cil_config.t_clk_settle = cil_clksettletime; + + if (mode && mode->signal_properties.shmoo_enable) { + cil_config.tuning.control = true; + cil_config.tuning.afe_hf_gain = mode->signal_properties.afe_hf_gain; + cil_config.tuning.edge_delay = mode->signal_properties.edge_delay; + dev_dbg(csi->dev, "Trying to override hfgain %d and edge-delay %d to RCE\n", + cil_config.tuning.afe_hf_gain, cil_config.tuning.edge_delay); + } if (s_data && !chan->pg_mode) cil_config.mipi_clock_rate = read_mipi_clk_from_dt(chan) / 1000; else cil_config.mipi_clock_rate = csi->clk_freq / 1000; + dev_dbg(csi->dev, "camera mipi_clock_rate %d\n", cil_config.mipi_clock_rate); + memset(&err_config, 0, sizeof(err_config)); /* Set NVCSI stream config */ memset(&msg, 0, sizeof(msg)); diff --git a/drivers/media/platform/tegra/camera/sensor_common.c b/drivers/media/platform/tegra/camera/sensor_common.c index 1de2ac35..440c18dd 100644 --- a/drivers/media/platform/tegra/camera/sensor_common.c +++ b/drivers/media/platform/tegra/camera/sensor_common.c @@ -67,6 +67,7 @@ static int sensor_common_parse_signal_props( int depth; u64 lane_rate; u64 symbol_rate; + int len = 0; err = of_property_read_string(node, "phy_mode", &temp_str); if (err) { @@ -85,6 +86,9 @@ static int sensor_common_parse_signal_props( } } + dev_dbg(dev, "%s: signal->phy_mode = %d(0: DPHY, 1: CPHY, 2: SLVS)\n", + __func__, signal->phy_mode); + /* Do not report error for these properties yet */ err = read_property_u32(node, "readout_orientation", &value); if (err) @@ -176,6 +180,20 @@ static int sensor_common_parse_signal_props( else signal->lane_polarity = value; + len = of_property_count_u32_elems(node, "lane_polarities"); + if (len > 0 && len <= 4) { + unsigned int lane_polarity_cphy[4] = {0}; + int err = of_property_read_u32_array(node, "lane_polarities", + lane_polarity_cphy, len); + if (!err) { + for (int i = 0; i < len; i++) { + signal->lane_polarities[i] = lane_polarity_cphy[i] & 0x7; + dev_dbg(dev, "lane_polarities: lane_polarity[%d] = %d\n", + i, signal->lane_polarities[i]); + } + } + } + /* initialize default if this prop not available */ err = of_property_read_string(node, "discontinuous_clk", &temp_str); if (!err) @@ -192,6 +210,35 @@ static int sensor_common_parse_signal_props( else signal->dpcm_enable = 0; + /* initialize default if this prop not available */ + err = of_property_read_string(node, "shmoo_enable", &temp_str); + if (!err) + signal->shmoo_enable = + !strncmp(temp_str, "true", sizeof("true")); + else + signal->shmoo_enable = 0; + + if (signal->shmoo_enable) { + err = read_property_u32(node, "afe_hf_gain", &value); + if (err) + signal->afe_hf_gain = 0; + else + signal->afe_hf_gain = value; + + err = read_property_u32(node, "edge_delay", &value); + if (err) + signal->edge_delay = 0; + else + signal->edge_delay = value; + } + + err = read_property_u32(node, "cil_clksettletime", &value); + if (err) + signal->cil_clksettletime = 0; + else + signal->cil_clksettletime = value; + + /* initialize default if this prop not available */ err = of_property_read_string(node, "deskew_initial_enable", &temp_str); diff --git a/include/media/tegra-v4l2-camera.h b/include/media/tegra-v4l2-camera.h index f39f8639..04139425 100644 --- a/include/media/tegra-v4l2-camera.h +++ b/include/media/tegra-v4l2-camera.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. +/* SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. * All rights reserved. * * TEGRA_V4L2_CAMERA.h - utilities for tegra camera driver @@ -110,7 +110,9 @@ struct sensor_signal_properties { __u32 mclk_freq; union __u64val pixel_clock; __u32 cil_settletime; + __u32 cil_clksettletime; __u32 lane_polarity; + __u32 lane_polarities[4]; __u32 discontinuous_clk; __u32 dpcm_enable; __u32 tegra_sinterface; @@ -119,6 +121,12 @@ struct sensor_signal_properties { __u32 deskew_periodic_enable; union __u64val serdes_pixel_clock; union __u64val mipi_clock; + + __u32 shmoo_enable; + /** @a afe_hf_gain [0,16] */ + __u32 afe_hf_gain; + /** @a edge_delay [-10,9] */ + __s32 edge_delay; }; struct sensor_image_properties {