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

From: Krzysztof Witos
Date: Tue Jun 26 2018 - 05:04:41 EST


Hi Maxime,

Thank you very much for the review. Yes, I understand your point.
This needs to be changed.

> 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


Best Regards,
Krzysztof