Commit cc9d3fa2 authored by Sowjanya Komatineni's avatar Sowjanya Komatineni Committed by Mauro Carvalho Chehab

media: tegra-video: Compute settle times based on the clock rate

Settle time determines the number of cil clock cyles to wait after
LP00 when moving from LP to HS.

This patch computes T-CLK-SETTLE and T-HS-SETTLE times based on cil
clock rate and pixel rate from the sensor and programs them during
streaming.

T-CLK-SETTLE time is the interval during which receiver will ignore
any HS transitions on clock lane starting from the beginning of
T-CLK-PREPARE.

T-HS-SETTLE time is the interval during which recevier will ignore
any HS transitions on data lane starting from the beginning of
T-HS-PREPARE.
Signed-off-by: default avatarSowjanya Komatineni <skomatineni@nvidia.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 523c857e
TODO list TODO list
* Add MIPI clock Settle time computation based on the data rate.
* Add support for Ganged mode. * Add support for Ganged mode.
* Add RAW10 packed video format support to Tegra210 video formats. * Add RAW10 packed video format support to Tegra210 video formats.
* Add support for suspend and resume. * Add support for suspend and resume.
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "csi.h" #include "csi.h"
#include "video.h" #include "video.h"
#define MHZ 1000000
static inline struct tegra_csi * static inline struct tegra_csi *
host1x_client_to_csi(struct host1x_client *client) host1x_client_to_csi(struct host1x_client *client)
{ {
...@@ -235,6 +237,59 @@ static int tegra_csi_g_frame_interval(struct v4l2_subdev *subdev, ...@@ -235,6 +237,59 @@ static int tegra_csi_g_frame_interval(struct v4l2_subdev *subdev,
return 0; return 0;
} }
static unsigned int csi_get_pixel_rate(struct tegra_csi_channel *csi_chan)
{
struct tegra_vi_channel *chan;
struct v4l2_subdev *src_subdev;
struct v4l2_ctrl *ctrl;
chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
src_subdev = tegra_channel_get_remote_source_subdev(chan);
ctrl = v4l2_ctrl_find(src_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
if (ctrl)
return v4l2_ctrl_g_ctrl_int64(ctrl);
return 0;
}
void tegra_csi_calc_settle_time(struct tegra_csi_channel *csi_chan,
u8 *clk_settle_time,
u8 *ths_settle_time)
{
struct tegra_csi *csi = csi_chan->csi;
unsigned int cil_clk_mhz;
unsigned int pix_clk_mhz;
int clk_idx = (csi_chan->csi_port_num >> 1) + 1;
cil_clk_mhz = clk_get_rate(csi->clks[clk_idx].clk) / MHZ;
pix_clk_mhz = csi_get_pixel_rate(csi_chan) / MHZ;
/*
* CLK Settle time is the interval during which HS receiver should
* ignore any clock lane HS transitions, starting from the beginning
* of T-CLK-PREPARE.
* Per DPHY specification, T-CLK-SETTLE should be between 95ns ~ 300ns
*
* 95ns < (clk-settle-programmed + 7) * lp clk period < 300ns
* midpoint = 197.5 ns
*/
*clk_settle_time = ((95 + 300) * cil_clk_mhz - 14000) / 2000;
/*
* THS Settle time is the interval during which HS receiver should
* ignore any data lane HS transitions, starting from the beginning
* of THS-PREPARE.
*
* Per DPHY specification, T-HS-SETTLE should be between 85ns + 6UI
* and 145ns+10UI.
* 85ns + 6UI < (Ths-settle-prog + 5) * lp_clk_period < 145ns + 10UI
* midpoint = 115ns + 8UI
*/
if (pix_clk_mhz)
*ths_settle_time = (115 * cil_clk_mhz + 8000 * cil_clk_mhz
/ (2 * pix_clk_mhz) - 5000) / 1000;
}
static int tegra_csi_enable_stream(struct v4l2_subdev *subdev) static int tegra_csi_enable_stream(struct v4l2_subdev *subdev)
{ {
struct tegra_vi_channel *chan = v4l2_get_subdev_hostdata(subdev); struct tegra_vi_channel *chan = v4l2_get_subdev_hostdata(subdev);
......
...@@ -51,6 +51,7 @@ struct tegra_csi; ...@@ -51,6 +51,7 @@ struct tegra_csi;
* @h_blank: horizontal blanking for TPG active format * @h_blank: horizontal blanking for TPG active format
* @v_blank: vertical blanking for TPG active format * @v_blank: vertical blanking for TPG active format
* @mipi: mipi device for corresponding csi channel pads * @mipi: mipi device for corresponding csi channel pads
* @pixel_rate: active pixel rate from the sensor on this channel
*/ */
struct tegra_csi_channel { struct tegra_csi_channel {
struct list_head list; struct list_head list;
...@@ -67,6 +68,7 @@ struct tegra_csi_channel { ...@@ -67,6 +68,7 @@ struct tegra_csi_channel {
unsigned int h_blank; unsigned int h_blank;
unsigned int v_blank; unsigned int v_blank;
struct tegra_mipi_device *mipi; struct tegra_mipi_device *mipi;
unsigned int pixel_rate;
}; };
/** /**
...@@ -147,4 +149,7 @@ extern const struct tegra_csi_soc tegra210_csi_soc; ...@@ -147,4 +149,7 @@ extern const struct tegra_csi_soc tegra210_csi_soc;
#endif #endif
void tegra_csi_error_recover(struct v4l2_subdev *subdev); void tegra_csi_error_recover(struct v4l2_subdev *subdev);
void tegra_csi_calc_settle_time(struct tegra_csi_channel *csi_chan,
u8 *clk_settle_time,
u8 *ths_settle_time);
#endif #endif
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* This source file contains Tegra210 supported video formats, * This source file contains Tegra210 supported video formats,
* VI and CSI SoC specific data, operations and registers accessors. * VI and CSI SoC specific data, operations and registers accessors.
*/ */
#include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/tegra.h> #include <linux/clk/tegra.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -98,6 +99,8 @@ ...@@ -98,6 +99,8 @@
#define BRICK_CLOCK_B_4X (0x2 << 16) #define BRICK_CLOCK_B_4X (0x2 << 16)
#define TEGRA_CSI_CIL_PAD_CONFIG1 0x004 #define TEGRA_CSI_CIL_PAD_CONFIG1 0x004
#define TEGRA_CSI_CIL_PHY_CONTROL 0x008 #define TEGRA_CSI_CIL_PHY_CONTROL 0x008
#define CLK_SETTLE_MASK GENMASK(13, 8)
#define THS_SETTLE_MASK GENMASK(5, 0)
#define TEGRA_CSI_CIL_INTERRUPT_MASK 0x00c #define TEGRA_CSI_CIL_INTERRUPT_MASK 0x00c
#define TEGRA_CSI_CIL_STATUS 0x010 #define TEGRA_CSI_CIL_STATUS 0x010
#define TEGRA_CSI_CILX_STATUS 0x014 #define TEGRA_CSI_CILX_STATUS 0x014
...@@ -770,8 +773,14 @@ static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan) ...@@ -770,8 +773,14 @@ static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan)
{ {
struct tegra_csi *csi = csi_chan->csi; struct tegra_csi *csi = csi_chan->csi;
unsigned int portno = csi_chan->csi_port_num; unsigned int portno = csi_chan->csi_port_num;
u8 clk_settle_time = 0;
u8 ths_settle_time = 10;
u32 val; u32 val;
if (!csi_chan->pg_mode)
tegra_csi_calc_settle_time(csi_chan, &clk_settle_time,
&ths_settle_time);
csi_write(csi, portno, TEGRA_CSI_CLKEN_OVERRIDE, 0); csi_write(csi, portno, TEGRA_CSI_CLKEN_OVERRIDE, 0);
/* clean up status */ /* clean up status */
...@@ -782,7 +791,9 @@ static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan) ...@@ -782,7 +791,9 @@ static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan)
/* CIL PHY registers setup */ /* CIL PHY registers setup */
cil_write(csi, portno, TEGRA_CSI_CIL_PAD_CONFIG0, 0x0); cil_write(csi, portno, TEGRA_CSI_CIL_PAD_CONFIG0, 0x0);
cil_write(csi, portno, TEGRA_CSI_CIL_PHY_CONTROL, 0xa); cil_write(csi, portno, TEGRA_CSI_CIL_PHY_CONTROL,
FIELD_PREP(CLK_SETTLE_MASK, clk_settle_time) |
FIELD_PREP(THS_SETTLE_MASK, ths_settle_time));
/* /*
* The CSI unit provides for connection of up to six cameras in * The CSI unit provides for connection of up to six cameras in
...@@ -801,7 +812,9 @@ static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan) ...@@ -801,7 +812,9 @@ static int tegra210_csi_start_streaming(struct tegra_csi_channel *csi_chan)
BRICK_CLOCK_A_4X); BRICK_CLOCK_A_4X);
cil_write(csi, portno + 1, TEGRA_CSI_CIL_PAD_CONFIG0, 0x0); cil_write(csi, portno + 1, TEGRA_CSI_CIL_PAD_CONFIG0, 0x0);
cil_write(csi, portno + 1, TEGRA_CSI_CIL_INTERRUPT_MASK, 0x0); cil_write(csi, portno + 1, TEGRA_CSI_CIL_INTERRUPT_MASK, 0x0);
cil_write(csi, portno + 1, TEGRA_CSI_CIL_PHY_CONTROL, 0xa); cil_write(csi, portno + 1, TEGRA_CSI_CIL_PHY_CONTROL,
FIELD_PREP(CLK_SETTLE_MASK, clk_settle_time) |
FIELD_PREP(THS_SETTLE_MASK, ths_settle_time));
csi_write(csi, portno, TEGRA_CSI_PHY_CIL_COMMAND, csi_write(csi, portno, TEGRA_CSI_PHY_CIL_COMMAND,
CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_ENABLE); CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_ENABLE);
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment