Re: [PATCH 2/2] added support for csirx dphy

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Fri, Jun 08, 2018 at 11:33:04AM +0100, Krzysztof Witos wrote:
> Signed-off-by: Krzysztof Witos <kwitos@xxxxxxxxxxx>

A commit log explaining what you're doing here would be nice.

> ---
>  drivers/media/platform/cadence/cdns-csi2rx.c | 342 ++++++++++++++++++++++++---
>  1 file changed, 313 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
> index a0f02916006b..9251ea6015f0 100644
> --- a/drivers/media/platform/cadence/cdns-csi2rx.c
> +++ b/drivers/media/platform/cadence/cdns-csi2rx.c
> @@ -2,14 +2,16 @@
>  /*
>   * Driver for Cadence MIPI-CSI2 RX Controller v1.3
>   *
> - * Copyright (C) 2017 Cadence Design Systems Inc.
> + * Copyright (C) 2017,2018 Cadence Design Systems Inc.
>   */
>  
>  #include <linux/clk.h>
> +#include <linux/iopoll.h>
>  #include <linux/delay.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_address.h>
>  #include <linux/of_graph.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> @@ -44,6 +46,33 @@
>  #define CSI2RX_LANES_MAX	4
>  #define CSI2RX_STREAMS_MAX	4
>  
> +/* DPHY registers */
> +#define DPHY_PMA_CMN(reg)       (reg)
> +#define DPHY_PMA_LCLK(reg)      (0x100 + (reg))
> +#define DPHY_PMA_LDATA(lane, reg)   (0x200 + ((lane) * 0x100) + (reg))
> +#define DPHY_PMA_RCLK(reg)      (0x600 + (reg))
> +#define DPHY_PMA_RDATA(lane, reg)   (0x700 + ((lane) * 0x100) + (reg))
> +#define DPHY_PCS(reg)           (0xb00 + (reg))
> +
> +#define DPHY_CMN_SSM            DPHY_PMA_CMN(0x20)
> +#define DPHY_CMN_SSM_EN         BIT(0)
> +#define DPHY_CMN_RX_MODE_EN     BIT(10)
> +
> +#define DPHY_CMN_PWM            DPHY_PMA_CMN(0x40)
> +#define DPHY_CMN_PWM_DIV(x)     ((x) << 20)
> +#define DPHY_CMN_PWM_LOW(x)     ((x) << 10)
> +#define DPHY_CMN_PWM_HIGH(x)        (x)
> +
> +#define DPHY_CMN_PLL_CFG	DPHY_PMA_CMN(0xE8)
> +#define PLL_LOCKED		BIT(2)
> +
> +#define DPHY_PSM_CFG            DPHY_PCS(0x4)
> +#define DPHY_PSM_CFG_FROM_REG       BIT(0)
> +#define DPHY_PSM_CLK_DIV(x)     ((x) << 1)
> +
> +#define DPHY_BAND_CTRL          DPHY_PCS(0x0)
> +#define DPHY_BAND_LEFT_VAL(x)	(x)
> +
>  enum csi2rx_pads {
>  	CSI2RX_PAD_SINK,
>  	CSI2RX_PAD_SOURCE_STREAM0,
> @@ -67,7 +96,7 @@ struct csi2rx_priv {
>  	struct clk			*sys_clk;
>  	struct clk			*p_clk;
>  	struct clk			*pixel_clk[CSI2RX_STREAMS_MAX];
> -	struct phy			*dphy;
> +	struct clk			*hs_clk;
>  
>  	u8				lanes[CSI2RX_LANES_MAX];
>  	u8				num_lanes;
> @@ -83,8 +112,175 @@ struct csi2rx_priv {
>  	struct v4l2_async_subdev	asd;
>  	struct v4l2_subdev		*source_subdev;
>  	int				source_pad;
> +	struct cdns_dphy		*dphy;
> +};
> +
> +struct cdns_dphy_cfg {
> +	unsigned int nlanes;
> +};
> +
> +struct cdns_dphy;
> +
> +enum cdns_dphy_clk_lane_cfg {
> +	DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0,
> +	DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1,
> +	DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2,
> +	DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3
> +};
> +
> +struct cdns_dphy_ops {
> +	int (*probe)(struct cdns_dphy *dphy);
> +	void (*remove)(struct cdns_dphy *dphy);
> +	void (*set_psm_div)(struct cdns_dphy *dphy, u8 div);
> +	void (*set_pll_cfg)(struct cdns_dphy *dphy);
> +	void (*set_clk_lane_cfg)(struct cdns_dphy *dphy,
> +		enum cdns_dphy_clk_lane_cfg cfg);
> +	void (*is_pll_locked)(struct cdns_dphy *dphy);
> +	void (*set_band_ctrl)(struct cdns_dphy *dphy, u8 value);
> +};
> +
> +struct cdns_dphy {
> +	struct cdns_dphy_cfg cfg;
> +	void __iomem *regs;
> +	struct clk *psm_clk;
> +	const struct cdns_dphy_ops *ops;
>  };
>  
> +static int cdns_dphy_set_band_ctrl(struct cdns_dphy *dphy,
> +	struct csi2rx_priv *csirx)
> +{
> +	u8 band_value;
> +	u32 hs_freq_mhz = clk_get_rate(csirx->hs_clk);
> +
> +	if (hs_freq_mhz >= 80 && hs_freq_mhz < 100)
> +		band_value = 0;
> +	else if (hs_freq_mhz >= 100 && hs_freq_mhz < 120)
> +		band_value = 1;
> +	else if (hs_freq_mhz >= 120 && hs_freq_mhz < 160)
> +		band_value = 2;
> +	else if (hs_freq_mhz >= 160 && hs_freq_mhz < 200)
> +		band_value = 3;
> +	else if (hs_freq_mhz >= 200 && hs_freq_mhz < 240)
> +		band_value = 4;
> +	else if (hs_freq_mhz >= 240 && hs_freq_mhz < 280)
> +		band_value = 5;
> +	else if (hs_freq_mhz >= 280 && hs_freq_mhz < 320)
> +		band_value = 6;
> +	else if (hs_freq_mhz >= 320 && hs_freq_mhz < 360)
> +		band_value = 7;
> +	else if (hs_freq_mhz >= 360 && hs_freq_mhz < 400)
> +		band_value = 8;
> +	else if (hs_freq_mhz >= 400 && hs_freq_mhz < 480)
> +		band_value = 9;
> +	else if (hs_freq_mhz >= 480 && hs_freq_mhz < 560)
> +		band_value = 10;
> +	else if (hs_freq_mhz >= 560 && hs_freq_mhz < 640)
> +		band_value = 11;
> +	else if (hs_freq_mhz >= 640 && hs_freq_mhz < 720)
> +		band_value = 12;
> +	else if (hs_freq_mhz >= 720 && hs_freq_mhz < 800)
> +		band_value = 13;
> +	else if (hs_freq_mhz >= 800 && hs_freq_mhz < 880)
> +		band_value = 14;
> +	else if (hs_freq_mhz >= 880 && hs_freq_mhz < 1040)
> +		band_value = 15;
> +	else if (hs_freq_mhz >= 1040 && hs_freq_mhz < 1200)
> +		band_value = 16;
> +	else if (hs_freq_mhz >= 1200 && hs_freq_mhz < 1350)
> +		band_value = 17;
> +	else if (hs_freq_mhz >= 1350 && hs_freq_mhz < 1500)
> +		band_value = 18;
> +	else if (hs_freq_mhz >= 1500 && hs_freq_mhz < 1750)
> +		band_value = 19;
> +	else if (hs_freq_mhz >= 1750 && hs_freq_mhz < 2000)
> +		band_value = 20;
> +	else if (hs_freq_mhz >= 2000 && hs_freq_mhz < 2250)
> +		band_value = 21;
> +	else if (hs_freq_mhz >= 2250 && hs_freq_mhz <= 2500)
> +		band_value = 22;
> +	else
> +		return -EINVAL;
> +
> +	if (dphy->ops->set_band_ctrl)
> +		dphy->ops->set_band_ctrl(dphy, band_value);
> +
> +	return 0;
> +}
> +
> +static int cdns_dphy_setup_psm(struct cdns_dphy *dphy)
> +{
> +	unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk);
> +	unsigned long psm_div;
> +
> +	if (!psm_clk_hz || psm_clk_hz > 100000000)
> +		return -EINVAL;
> +
> +	psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000);
> +	if (dphy->ops->set_psm_div)
> +		dphy->ops->set_psm_div(dphy, psm_div);
> +
> +	return 0;
> +}
> +
> +static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy,
> +	enum cdns_dphy_clk_lane_cfg cfg)
> +{
> +	if (dphy->ops->set_clk_lane_cfg)
> +		dphy->ops->set_clk_lane_cfg(dphy, cfg);
> +}
> +
> +static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy)
> +{
> +	if (dphy->ops->set_pll_cfg)
> +		dphy->ops->set_pll_cfg(dphy);
> +}
> +
> +static void cdns_dphy_is_pll_locked(struct cdns_dphy *dphy)
> +{
> +	if (dphy->ops->is_pll_locked)
> +		dphy->ops->is_pll_locked(dphy);
> +}
> +
> +static void cdns_csirx_dphy_init(struct csi2rx_priv *csi2rx,
> +	const struct cdns_dphy_cfg *dphy_cfg)
> +{
> +
> +	/*
> +	 * Configure the band control settings.
> +	 */
> +	cdns_dphy_set_band_ctrl(csi2rx->dphy, csi2rx);
> +
> +	/*
> +	 * Configure the internal PSM clk divider so that the DPHY has a
> +	 * 1MHz clk (or something close).
> +	 */
> +	WARN_ON_ONCE(cdns_dphy_setup_psm(csi2rx->dphy));
> +
> +	/*
> +	 * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes
> +	 * and 8 data lanes, each clk lane can be attache different set of
> +	 * data lanes. The 2 groups are named 'left' and 'right', so here we
> +	 * just say that we want the 'left' clk lane to drive the 'left' data
> +	 * lanes.
> +	 */
> +	cdns_dphy_set_clk_lane_cfg(csi2rx->dphy,
> +		DPHY_CLK_CFG_LEFT_DRIVES_LEFT);
> +
> +	/*
> +	 * Configure the DPHY PLL that will be used to generate the TX byte
> +	 * clk.
> +	 */
> +	cdns_dphy_set_pll_cfg(csi2rx->dphy);
> +
> +	/*  Start RX state machine. */
> +	writel(DPHY_CMN_SSM_EN | DPHY_CMN_RX_MODE_EN,
> +		csi2rx->dphy->regs + DPHY_CMN_SSM);
> +
> +	/* Checking if PLL is locked */
> +	cdns_dphy_is_pll_locked(csi2rx->dphy);
> +
> +}
> +

That part looks like it's pretty much the same thing than the PHY
support in the DSI bridge found there:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/bridge/cdns-dsi.c#n493

This code shouldn't be duplicated, but shared, ideally through the phy
framework. That would require some changes to that framework though.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux