[PATCH 05/16] media: cadence: csi2rx: Add external DPHY support

Tomi Valkeinen tomi.valkeinen at ideasonboard.com
Thu Apr 8 09:22:39 BST 2021


On 08/04/2021 11:13, Chunfeng Yun wrote:
> On Wed, 2021-04-07 at 00:24 +0530, Pratyush Yadav wrote:
>> On 31/03/21 05:24PM, Chunfeng Yun wrote:
>>> On Tue, 2021-03-30 at 23:03 +0530, Pratyush Yadav wrote:
>>>> Some platforms like TI's J721E can have the CSI2RX paired with an
>>>> external DPHY. Add support to enable and configure the DPHY using the
>>>> generic PHY framework.
>>>>
>>>> Get the pixel rate and bpp from the subdev and pass them on to the DPHY
>>>> along with the number of lanes. All other settings are left to their
>>>> default values.
>>>>
>>>> Signed-off-by: Pratyush Yadav <p.yadav at ti.com>
>>>> ---
>>>>   drivers/media/platform/cadence/cdns-csi2rx.c | 147 +++++++++++++++++--
>>>>   1 file changed, 137 insertions(+), 10 deletions(-)
>>>>
>>>> diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
>>>> index c68a3eac62cd..31bd80e3f780 100644
>>>> --- a/drivers/media/platform/cadence/cdns-csi2rx.c
>>>> +++ b/drivers/media/platform/cadence/cdns-csi2rx.c
>>>> @@ -30,6 +30,12 @@
>>>>   #define CSI2RX_STATIC_CFG_DLANE_MAP(llane, plane)	((plane) << (16 + (llane) * 4))
>>>>   #define CSI2RX_STATIC_CFG_LANES_MASK			GENMASK(11, 8)
>>>>   
>>>> +#define CSI2RX_DPHY_LANE_CTRL_REG		0x40
>>>> +#define CSI2RX_DPHY_CL_RST			BIT(16)
>>>> +#define CSI2RX_DPHY_DL_RST(i)			BIT((i) + 12)
>>>> +#define CSI2RX_DPHY_CL_EN			BIT(4)
>>>> +#define CSI2RX_DPHY_DL_EN(i)			BIT(i)
>>>> +
>>>>   #define CSI2RX_STREAM_BASE(n)		(((n) + 1) * 0x100)
>>>>   
>>>>   #define CSI2RX_STREAM_CTRL_REG(n)		(CSI2RX_STREAM_BASE(n) + 0x000)
>>>> @@ -54,6 +60,11 @@ enum csi2rx_pads {
>>>>   	CSI2RX_PAD_MAX,
>>>>   };
>>>>   
>>>> +struct csi2rx_fmt {
>>>> +	u32				code;
>>>> +	u8				bpp;
>>>> +};
>>>> +
>>>>   struct csi2rx_priv {
>>>>   	struct device			*dev;
>>>>   	unsigned int			count;
>>>> @@ -85,6 +96,52 @@ struct csi2rx_priv {
>>>>   	int				source_pad;
>>>>   };
>>>>   
>>>> +static const struct csi2rx_fmt formats[] = {
>>>> +	{
>>>> +		.code	= MEDIA_BUS_FMT_YUYV8_2X8,
>>>> +		.bpp	= 16,
>>>> +	},
>>>> +	{
>>>> +		.code	= MEDIA_BUS_FMT_UYVY8_2X8,
>>>> +		.bpp	= 16,
>>>> +	},
>>>> +	{
>>>> +		.code	= MEDIA_BUS_FMT_YVYU8_2X8,
>>>> +		.bpp	= 16,
>>>> +	},
>>>> +	{
>>>> +		.code	= MEDIA_BUS_FMT_VYUY8_2X8,
>>>> +		.bpp	= 16,
>>>> +	},
>>>> +};
>>>> +
>>>> +static u8 csi2rx_get_bpp(u32 code)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(formats); i++) {
>>>> +		if (formats[i].code == code)
>>>> +			return formats[i].bpp;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static s64 csi2rx_get_pixel_rate(struct csi2rx_priv *csi2rx)
>>>> +{
>>>> +	struct v4l2_ctrl *ctrl;
>>>> +
>>>> +	ctrl = v4l2_ctrl_find(csi2rx->source_subdev->ctrl_handler,
>>>> +			      V4L2_CID_PIXEL_RATE);
>>>> +	if (!ctrl) {
>>>> +		dev_err(csi2rx->dev, "no pixel rate control in subdev: %s\n",
>>>> +			csi2rx->source_subdev->name);
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	return v4l2_ctrl_g_ctrl_int64(ctrl);
>>>> +}
>>>> +
>>>>   static inline
>>>>   struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev)
>>>>   {
>>>> @@ -101,6 +158,55 @@ static void csi2rx_reset(struct csi2rx_priv *csi2rx)
>>>>   	writel(0, csi2rx->base + CSI2RX_SOFT_RESET_REG);
>>>>   }
>>>>   
>>>> +static int csi2rx_configure_external_dphy(struct csi2rx_priv *csi2rx)
>>>> +{
>>>> +	union phy_configure_opts opts = { };
>>>> +	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
>>>> +	struct v4l2_subdev_format sd_fmt;
>>>> +	s64 pixel_rate;
>>>> +	int ret;
>>>> +	u8 bpp;
>>>> +
>>>> +	sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>>>> +	sd_fmt.pad = 0;
>>>> +
>>>> +	ret = v4l2_subdev_call(csi2rx->source_subdev, pad, get_fmt, NULL,
>>>> +			       &sd_fmt);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	bpp = csi2rx_get_bpp(sd_fmt.format.code);
>>>> +	if (!bpp)
>>>> +		return -EINVAL;
>>>> +
>>>> +	pixel_rate = csi2rx_get_pixel_rate(csi2rx);
>>>> +	if (pixel_rate < 0)
>>>> +		return pixel_rate;
>>>> +
>>>> +	ret = phy_mipi_dphy_get_default_config(pixel_rate, bpp,
>>>> +					       csi2rx->num_lanes, cfg);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	ret = phy_set_mode_ext(csi2rx->dphy, PHY_MODE_MIPI_DPHY,
>>>> +			       PHY_MIPI_DPHY_SUBMODE_RX);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	ret = phy_power_on(csi2rx->dphy);
>>>> +	if (ret)
>>>> +		return ret;
>>> Seems phy_power_on, then phy_set_mode_ext?
>>
>> Shouldn't the mode be set before the PHY is powered on so the correct
>> power on procedure can be performed based on the mode of operation?
> Of course, it is fine for cnds-dphy.
> But it depends on HW design and also phy driver;
> if the mode is controlled in PHY IP register, we can't access it before
> phy_power_on if no phy_init called (e.g. clock/power is not enabled).
> 
> Just let you pay attention on the phy sequence.

I don't think the phy configuration should depend on phy_power_on, but 
the runtime PM.

I guess this could be solved with:

phy_pm_runtime_get_sync();
phy_set_mode_ext();
phy_power_on();
phy_pm_runtime_put();

  Tomi



More information about the linux-phy mailing list