From 033935acd9b1be2f71b2dd980e38d00e13ad29b2 Mon Sep 17 00:00:00 2001 From: Bhanu Murthy V Date: Thu, 11 Jan 2018 18:41:39 -0800 Subject: drivers: camera: CPHY calibration support Add proper phy mode read support from device tree to distinguish CPHY and DPHY sensor modes. Fix CPHY calibration flow to write CPHY mode and complete calibration. Bug 1946718 Change-Id: I801965207a6777aa71cc5fc24fcb0a7e0c487093 Signed-off-by: Bhanu Murthy V Reviewed-on: https://git-master.nvidia.com/r/1639635 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/media/platform/tegra/camera/csi/csi.c | 65 +++++++++++++++++++++- .../media/platform/tegra/camera/csi/csi4_fops.c | 53 +++++------------- .../media/platform/tegra/camera/nvcsi/csi5_fops.c | 15 +++-- .../media/platform/tegra/camera/sensor_common.c | 17 +++++- drivers/media/platform/tegra/mipical/mipi_cal.c | 18 +++--- include/media/csi.h | 4 +- include/media/tegra-v4l2-camera.h | 8 ++- 7 files changed, 124 insertions(+), 56 deletions(-) diff --git a/drivers/media/platform/tegra/camera/csi/csi.c b/drivers/media/platform/tegra/camera/csi/csi.c index bf7bb744f..c140b1b5e 100644 --- a/drivers/media/platform/tegra/camera/csi/csi.c +++ b/drivers/media/platform/tegra/camera/csi/csi.c @@ -1,7 +1,7 @@ /* * NVIDIA Tegra CSI Device * - * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015-2018, NVIDIA CORPORATION. All rights reserved. * * Author: Bryan Wu * @@ -72,6 +72,69 @@ static void update_blank_intervals(struct tegra_csi_channel *chan, port->v_blank = tegra_csi_tpg_frmfmt[fmtindex].v_blank; } +static struct sensor_mode_properties* +read_mode_from_dt(struct camera_common_data *s_data) +{ + struct sensor_mode_properties *mode = NULL; + + if (s_data) { + int idx = s_data->mode_prop_idx; + + if (idx < s_data->sensor_props.num_modes) + mode = &s_data->sensor_props.sensor_modes[idx]; + } + + return mode; +} + +u32 read_settle_time_from_dt(struct tegra_csi_channel *chan) +{ + struct camera_common_data *s_data = chan->s_data; + struct sensor_mode_properties *mode = read_mode_from_dt(s_data); + struct device *dev = chan->csi->dev; + unsigned int cil_settletime = 0; + + if (mode) { + dev_dbg(dev, "settle time reading from props\n"); + cil_settletime = mode->signal_properties.cil_settletime; + } else if (chan->of_node) { + int err = 0; + const char *str; + + dev_dbg(dev, "settle time reading from of_node\n"); + err = of_property_read_string(chan->of_node, "cil_settletime", + &str); + if (!err) { + err = kstrtou32(str, 10, &cil_settletime); + if (err) { + dev_dbg(dev, + "no cil_settletime in of_node"); + cil_settletime = 0; + } + } + } + + return cil_settletime; +} + +u32 read_phy_mode_from_dt(struct tegra_csi_channel *chan) +{ + struct camera_common_data *s_data = chan->s_data; + struct sensor_mode_properties *mode = read_mode_from_dt(s_data); + struct device *dev = chan->csi->dev; + u32 phy_mode = 0; + + if (mode) { + dev_dbg(dev, "settle time reading from props\n"); + phy_mode = mode->signal_properties.phy_mode; + } else { + dev_dbg(dev, "phy mode unavailable in props, use default\n"); + phy_mode = CSI_PHY_MODE_DPHY; + } + + return phy_mode; +} + void set_csi_portinfo(struct tegra_csi_device *csi, unsigned int port, unsigned int numlanes) { diff --git a/drivers/media/platform/tegra/camera/csi/csi4_fops.c b/drivers/media/platform/tegra/camera/csi/csi4_fops.c index fee0f47d3..0e264e6fb 100644 --- a/drivers/media/platform/tegra/camera/csi/csi4_fops.c +++ b/drivers/media/platform/tegra/camera/csi/csi4_fops.c @@ -1,7 +1,7 @@ /* * Tegra CSI4 device common APIs * - * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. * * Author: Frank Chen * @@ -102,14 +102,11 @@ static void csi4_stream_config(struct tegra_csi_channel *chan, int port_num) __func__, port_num, val); } - static void csi4_phy_config( struct tegra_csi_channel *chan, int csi_port, int csi_lanes, bool enable) { struct tegra_csi_device *csi = chan->csi; - struct camera_common_data *s_data = chan->s_data; - const struct sensor_mode_properties *mode = NULL; int phy_num = (csi_port & 0x6) >> 1; bool cil_a = (csi_port & 0x1) ? false : true; int cil_config; @@ -117,12 +114,14 @@ static void csi4_phy_config( const unsigned int cil_clk_mhz = TEGRA_CSICIL_CLK_MHZ; const unsigned int csi_clk_mhz = csi->clk_freq / 1000000; /* Calculated clock settling times for cil and csi clocks */ - unsigned int cil_settletime = 0; + unsigned int cil_settletime = read_settle_time_from_dt(chan); unsigned int csi_settletime; + u32 phy_mode = read_phy_mode_from_dt(chan); dev_dbg(csi->dev, "%s\n", __func__); - if (csi_lanes == 3) /* set to CPHY */ + + if (phy_mode == CSI_PHY_MODE_CPHY) /* set to CPHY */ csi4_phy_write(chan, phy_num, NVCSI_CIL_PHY_CTRL, CPHY); else /* set to DPHY */ csi4_phy_write(chan, phy_num, NVCSI_CIL_PHY_CTRL, DPHY); @@ -186,36 +185,6 @@ static void csi4_phy_config( /* power on de-serializer */ csi4_phy_write(chan, phy_num, NVCSI_CIL_PAD_CONFIG, 0); - /* Attempt to find the cil_settingtime from the device tree */ - if (s_data) { - int idx = s_data->mode_prop_idx; - - dev_dbg(csi->dev, "cil_settingtime is pulled from device"); - if (idx < s_data->sensor_props.num_modes) { - mode = &s_data->sensor_props.sensor_modes[idx]; - cil_settletime = mode->signal_properties.cil_settletime; - } else { - dev_dbg(csi->dev, "mode not listed in DT, use default"); - cil_settletime = 0; - } - } else if (chan->of_node) { - int err = 0; - const char *str; - - dev_dbg(csi->dev, - "cil_settletime is pulled from device of_node"); - err = of_property_read_string(chan->of_node, "cil_settletime", - &str); - if (!err) { - err = kstrtou32(str, 10, &cil_settletime); - if (err) { - dev_dbg(csi->dev, - "no cil_settletime in of_node"); - cil_settletime = 0; - } - } - } - /* calculate MIPI settling times */ dev_dbg(csi->dev, "cil core clock: %u, csi clock: %u", cil_clk_mhz, csi_clk_mhz); @@ -252,7 +221,7 @@ static void csi4_phy_config( csi4_phy_write(chan, phy_num, NVCSI_CIL_A_SW_RESET, 0x0); /* setting up CIL B for 3 lane CPHY */ - if (csi_lanes == 3) { + if (phy_mode == CSI_PHY_MODE_CPHY) { /* set this to reset for pushing more settings */ csi4_phy_write(chan, phy_num, NVCSI_CIL_A_SW_RESET, SW_RESET1_EN | SW_RESET0_EN); @@ -619,6 +588,8 @@ static int csi4_mipi_cal(struct tegra_csi_channel *chan) unsigned int lanes, num_ports, port, addr; unsigned int cila, cilb; struct tegra_csi_device *csi = chan->csi; + u32 phy_mode = read_phy_mode_from_dt(chan); + bool is_cphy = (phy_mode == CSI_PHY_MODE_CPHY); lanes = 0; num_ports = 0; @@ -633,7 +604,7 @@ static int csi4_mipi_cal(struct tegra_csi_channel *chan) NVCSI_CIL_A_SW_RESET : NVCSI_CIL_B_SW_RESET); csi4_phy_write(chan, port >> 1, addr, SW_RESET1_EN | SW_RESET0_EN); - } else if (chan->numlanes == 3) { /* CPHY */ + } else if (chan->numlanes == 3) { lanes |= (CSIA | CSIB) << port; cila = (0x01 << E_INPUT_LP_IO0_SHIFT) | (0x01 << E_INPUT_LP_IO1_SHIFT) | @@ -651,7 +622,10 @@ static int csi4_mipi_cal(struct tegra_csi_channel *chan) NVCSI_CIL_A_BASE + PAD_CONFIG_0, cila); csi4_phy_write(chan, port >> 1, NVCSI_CIL_B_BASE + PAD_CONFIG_0, cilb); - return 0; /*TODO configure and enable mipical for cphy*/ + csi4_phy_write(chan, port >> 1, NVCSI_CIL_A_SW_RESET, + SW_RESET1_EN | SW_RESET0_EN); + csi4_phy_write(chan, port >> 1, NVCSI_CIL_B_SW_RESET, + SW_RESET1_EN | SW_RESET0_EN); } else { lanes |= (CSIA | CSIB) << port; cila = (0x01 << E_INPUT_LP_IO0_SHIFT) | @@ -680,6 +654,7 @@ static int csi4_mipi_cal(struct tegra_csi_channel *chan) dev_err(csi->dev, "Selected no CSI lane, cannot do calibration"); return -EINVAL; } + lanes |= is_cphy ? 0x1 : 0; return tegra_mipi_calibration(lanes); } struct tegra_csi_fops csi4_fops = { diff --git a/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c b/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c index c4b6c804f..5bc49f0d0 100644 --- a/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c +++ b/drivers/media/platform/tegra/camera/nvcsi/csi5_fops.c @@ -1,7 +1,7 @@ /* * Tegra CSI5 device common APIs * - * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. * * Author: Frank Chen * @@ -171,6 +171,8 @@ static int csi5_mipi_cal(struct tegra_csi_channel *chan) unsigned int lanes, num_ports, port, addr; unsigned int cila, cilb; struct tegra_csi_device *csi = chan->csi; + u32 phy_mode = read_phy_mode_from_dt(chan); + bool is_cphy = (phy_mode == CSI_PHY_MODE_CPHY); lanes = 0; num_ports = 0; @@ -186,7 +188,7 @@ static int csi5_mipi_cal(struct tegra_csi_channel *chan) CSI5_NVCSI_CIL_B_SW_RESET); csi5_phy_write(chan, port >> 1, addr, CSI5_SW_RESET1_EN | CSI5_SW_RESET0_EN); - } else if (chan->numlanes == 3) { /* CPHY */ + } else if (chan->numlanes == 3) { lanes |= (CSIA | CSIB) << port; cila = (0x01 << CSI5_E_INPUT_LP_IO0_SHIFT) | (0x01 << CSI5_E_INPUT_LP_IO1_SHIFT) | @@ -206,8 +208,12 @@ static int csi5_mipi_cal(struct tegra_csi_channel *chan) csi5_phy_write(chan, port >> 1, CSI5_NVCSI_CIL_B_BASE + CSI5_PAD_CONFIG_0, cilb); - /*TODO configure and enable mipical for cphy*/ - return 0; + csi5_phy_write(chan, port >> 1, + CSI5_NVCSI_CIL_A_SW_RESET, + CSI5_SW_RESET1_EN | CSI5_SW_RESET0_EN); + csi5_phy_write(chan, port >> 1, + CSI5_NVCSI_CIL_B_SW_RESET, + CSI5_SW_RESET1_EN | CSI5_SW_RESET0_EN); } else { lanes |= (CSIA | CSIB) << port; cila = (0x01 << CSI5_E_INPUT_LP_IO0_SHIFT) | @@ -241,6 +247,7 @@ static int csi5_mipi_cal(struct tegra_csi_channel *chan) "Selected no CSI lane, cannot do calibration"); return -EINVAL; } + lanes |= is_cphy ? 0x1 : 0; return tegra_mipi_calibration(lanes); } diff --git a/drivers/media/platform/tegra/camera/sensor_common.c b/drivers/media/platform/tegra/camera/sensor_common.c index a5482e7c0..6d1723ff8 100644 --- a/drivers/media/platform/tegra/camera/sensor_common.c +++ b/drivers/media/platform/tegra/camera/sensor_common.c @@ -1,7 +1,7 @@ /* * sensor_common.c - utilities for tegra sensor drivers * - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -142,6 +142,21 @@ static int sensor_common_parse_signal_props( return -EINVAL; } + err = of_property_read_string(node, "phy_mode", &temp_str); + if (err) { + dev_dbg(dev, "%s: use default phy mode DPHY\n", __func__); + signal->phy_mode = CSI_PHY_MODE_DPHY; + } else { + if (strcmp(temp_str, "CPHY") == 0) + signal->phy_mode = CSI_PHY_MODE_CPHY; + else if (strcmp(temp_str, "DPHY") == 0) + signal->phy_mode = CSI_PHY_MODE_DPHY; + else { + dev_err(dev, "%s: Invalid Phy mode\n", __func__); + return -EINVAL; + } + } + return 0; } diff --git a/drivers/media/platform/tegra/mipical/mipi_cal.c b/drivers/media/platform/tegra/mipical/mipi_cal.c index 8664b338e..5e762778f 100644 --- a/drivers/media/platform/tegra/mipical/mipi_cal.c +++ b/drivers/media/platform/tegra/mipical/mipi_cal.c @@ -1,7 +1,7 @@ /* * mipi_cal.c * - * Copyright (c) 2016-2017, NVIDIA CORPORATION, All rights reserved. + * Copyright (c) 2016-2018, NVIDIA CORPORATION, All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -649,25 +649,27 @@ err: return -ENODEV; } #endif -static int tegra_mipical_using_prod(struct tegra_mipi *mipi, int lanes) +static int tegra_mipical_using_prod(struct tegra_mipi *mipi, int lanes_info) { - int err = -1, val = 0; + int err = -1; int i; u32 csi_mask = 0; - + int is_cphy = lanes_info & 0x1; + u32 lanes = 0; for (i = 0; i < mipi->soc->total_cillanes; ++i) csi_mask |= (CSIA << i); + lanes = lanes_info - is_cphy; mutex_lock(&mipi->lock); /* clean up lanes */ clear_all(mipi); /* Apply MIPI_CAL PROD_Set */ - regmap_read(mipi->regmap, ADDR(MIPI_CAL_MODE), &val); + mipical_write(mipi->regmap, ADDR(MIPI_CAL_MODE), is_cphy); - if (val & SEL_DPHY_CPHY) { /*CPHY*/ + if (is_cphy) { /*CPHY*/ err = tegra_mipical_prodset_helper(mipi, "prod"); if (err) @@ -685,7 +687,7 @@ static int tegra_mipical_using_prod(struct tegra_mipi *mipi, int lanes) goto prod_set_fail; err = tegra_mipical_prodset_helper(mipi, - "prod_c_dphy_csi"); + "prod_c_dphy_csi"); if (err) goto prod_set_fail; @@ -695,7 +697,7 @@ static int tegra_mipical_using_prod(struct tegra_mipi *mipi, int lanes) goto prod_set_fail; err = tegra_mipical_prodset_helper(mipi, - "prod_c_dphy_dsi"); + "prod_c_dphy_dsi"); if (err) goto prod_set_fail; diff --git a/include/media/csi.h b/include/media/csi.h index 6b7c8fe42..6a72d34b3 100644 --- a/include/media/csi.h +++ b/include/media/csi.h @@ -1,7 +1,7 @@ /* * NVIDIA Tegra CSI Device Header * - * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2015-2018, NVIDIA CORPORATION. All rights reserved. * * Author: Bryan Wu * @@ -139,6 +139,8 @@ static inline struct tegra_csi_device *to_csi(struct v4l2_subdev *subdev) return chan->csi; } +u32 read_phy_mode_from_dt(struct tegra_csi_channel *chan); +u32 read_settle_time_from_dt(struct tegra_csi_channel *chan); void set_csi_portinfo(struct tegra_csi_device *csi, unsigned int port, unsigned int numlanes); void tegra_csi_status(struct tegra_csi_channel *chan, diff --git a/include/media/tegra-v4l2-camera.h b/include/media/tegra-v4l2-camera.h index 4b6b54e47..4b8f306db 100644 --- a/include/media/tegra-v4l2-camera.h +++ b/include/media/tegra-v4l2-camera.h @@ -1,7 +1,7 @@ /** * TEGRA_V4L2_CAMERA.h - utilities for tegra camera driver * - * Copyright (c) 2017, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2017-2018, NVIDIA Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -72,6 +72,9 @@ #define TEGRA_CAM_STRING_CTRL_FUSEID_INDEX 1 #define TEGRA_CAM_STRING_CTRL_OTP_INDEX 2 +#define CSI_PHY_MODE_DPHY 0 +#define CSI_PHY_MODE_CPHY 1 + struct unpackedU64 { __u32 high; __u32 low; @@ -91,7 +94,8 @@ struct sensor_signal_properties { __u32 discontinuous_clk; __u32 dpcm_enable; __u32 tegra_sinterface; - __u32 reserved[7]; + __u32 phy_mode; + __u32 reserved[6]; }; struct sensor_image_properties { -- cgit v1.2.2