Re: [PATCH v13 2/2] rcar-csi2: add Renesas R-Car MIPI CSI-2 receiver driver

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

 



Hi Jacopo,

Thanks for your feedback.

Comments I have snipped out from this reply are addressed, thanks for 
bringing them to my attention!

On 2018-04-05 11:10:01 +0200, Jacopo Mondi wrote:

[snip]

> > +static int rcar_csi2_wait_phy_start(struct rcar_csi2 *priv)
> > +{
> > +	int timeout;
> > +
> > +	/* Wait for the clock and data lanes to enter LP-11 state. */
> > +	for (timeout = 100; timeout > 0; timeout--) {
> > +		const u32 lane_mask = (1 << priv->lanes) - 1;
> > +
> > +		if ((rcar_csi2_read(priv, PHCLM_REG) & 1) == 1 &&
> 
> Nitpicking:
> 		if ((rcar_csi2_read(priv, PHCLM_REG) & 0x01) &&
> 
> Don't you prefer to provide defines also for bit fields instead of
> using magic values? In this case something like
> PHCLM_REG_STOPSTATE_CLK would do.

Thanks addressed per your and Kieran's suggestion.

> 
> Also, from tables 25.[17-20] it seems to me that for H3 and V3 you
> have to set INSTATE to an hardcoded value after having validated PHDLM.
> Maybe it is not necessary, just pointing it out.

I assume you mean Figures 25.[17-20] and not Tables as the last table in 
chapter 25 is Table 25.15 and the register in question is INTSTATE :-) 
And to clarify this is documented for H3 which this driver supports and 
V3H and M3-N which this driver dose not yet support. And the constant 
you are to set it to is ULPS_START | UPLS_END.

This is a good catch as this was introduced in a later version of the 
datasheet and the current code where the ULPS_START | UPLS_END is set 
before confirming LP-11 have kept on working. Check the 
priv->info->clear_ulps usage in rcar_csi2_start(). I do think it's 
better to follow the flow-chart in the new datasheet so I will move this 
to the end of rcar_csi2_start() to reflect that (provided that the end 
result still works :-) Thanks for pointing this out!

[snip]

> > +static int rcar_csi2_start(struct rcar_csi2 *priv)
> > +{
> > +	const struct rcar_csi2_format *format;
> > +	u32 phycnt, phypll, vcdt = 0, vcdt2 = 0;
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
> > +		priv->mf.width, priv->mf.height,
> > +		priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i');
> > +
> > +	/* Code is validated in set_fmt */
> > +	format = rcar_csi2_code_to_fmt(priv->mf.code);
> > +
> > +	/*
> > +	 * Enable all Virtual Channels
> > +	 *
> > +	 * NOTE: It's not possible to get individual datatype for each
> > +	 *       source virtual channel. Once this is possible in V4L2
> > +	 *       it should be used here.
> > +	 */
> > +	for (i = 0; i < 4; i++) {
> > +		u32 vcdt_part;
> > +
> > +		vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
> > +			VCDT_SEL_DT(format->datatype);
> > +
> > +		/* Store in correct reg and offset */
> > +		if (i < 2)
> > +			vcdt |= vcdt_part << ((i % 2) * 16);
> > +		else
> > +			vcdt2 |= vcdt_part << ((i % 2) * 16);
> > +	}
> > +
> > +	switch (priv->lanes) {
> > +	case 1:
> > +		phycnt = PHYCNT_ENABLECLK | PHYCNT_ENABLE_0;
> > +		break;
> > +	case 2:
> > +		phycnt = PHYCNT_ENABLECLK | PHYCNT_ENABLE_1 | PHYCNT_ENABLE_0;
> > +		break;
> > +	case 4:
> > +		phycnt = PHYCNT_ENABLECLK | PHYCNT_ENABLE_3 | PHYCNT_ENABLE_2 |
> > +			PHYCNT_ENABLE_1 | PHYCNT_ENABLE_0;
> > +		break;
> 
> Even simpler this could be written as
> 
>                 phycnt = PHYCNT_ENABLECLK | (1 << priv->lanes) - 1;

Fixed per your and Geert's suggestion.

> 
> > +	default:
> > +		return -EINVAL;
> 
> Can this happen? You have validated priv->lanes already when parsing
> DT

This can't happen but I like to have a catch all in any case, but since 
I took yours and Geert's suggestion above this issue goes away :-)

> 
> > +	}
> > +
> > +	ret = rcar_csi2_calc_phypll(priv, format->bpp, &phypll);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Clear Ultra Low Power interrupt */
> > +	if (priv->info->clear_ulps)
> > +		rcar_csi2_write(priv, INTSTATE_REG,
> > +				INTSTATE_INT_ULPS_START |
> > +				INTSTATE_INT_ULPS_END);
> > +
> > +	/* Init */
> > +	rcar_csi2_write(priv, TREF_REG, TREF_TREF);
> > +	rcar_csi2_reset(priv);
> > +	rcar_csi2_write(priv, PHTC_REG, 0);
> > +
> > +	/* Configure */
> > +	rcar_csi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 |
> > +			FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN);
> 
> On the FLD_FLD_NUM(2) mask. Why 2?
> I read on the datasheet "the register must not be changed from default
> value" and I read defaul to be 0x0000

This is based on feedback from Renesas. The register is not properly 
documented. I'm working on improving it but for now I would like to keep 
it as FLD_FLD_NUM(2) and make a neater and documented fix in a follow up 
commit. In short it controls which field is captured first (ODD/EVEN).

> 
> Also, please consider a make as all other fields are enabled
> unconditionally.

No I don't like the idea of a mask here, I feel it better to be 
explicit.

> 
> > +	rcar_csi2_write(priv, VCDT_REG, vcdt);
> > +	rcar_csi2_write(priv, VCDT2_REG, vcdt2);
> > +	/* Lanes are zero indexed */
> > +	rcar_csi2_write(priv, LSWAP_REG,
> > +			LSWAP_L0SEL(priv->lane_swap[0] - 1) |
> > +			LSWAP_L1SEL(priv->lane_swap[1] - 1) |
> > +			LSWAP_L2SEL(priv->lane_swap[2] - 1) |
> > +			LSWAP_L3SEL(priv->lane_swap[3] - 1));
> 
> EDIT:
> (This comment is way too long for the real value it has, but since I
> already wrote it, and my initial doubt clarified while I was writing,
> resulting in a much less serious issues, I'm gonna keep it all anyway.
> Sorry about this :)
> 
> Why - 1 ?
> Is this because it is assumed clock lane is in position 0? Is this
> fixed by design?
> 
> What I read in datasheet for LSWAP_REG is:
> L[0-3]SEL       0 = Use PHY lane 0
>                 1 = Use PHY lane 1
>                 2 = Use PHY lane 2
>                 3 = Use PHY lane 3
> 
> priv->lane_swap[i] is collected parsing 'data_lanes' property and
> should reflect the actual physical lane value assigned to logical lane
> numbers. If 'data_lanes' is, say <1 2> I expect
> 
> priv->lane_swap[0] = 1;
> priv->lane_swap[1] = 2;
> priv->lane_swap[1] = 3; //assigned by your parsing routine
> priv->lane_swap[1] = 4; //assigned by your parsing routine
> 
> And I understand LSWAP counts instead from [0-3] so, ok, I get why you
> subtract one. But now I wonder what happens if instead, lane position
> is specified counting from 0 in DT. Ah, I see you refuse lane_swap
> values < 1! So It should be assumed clock is by HW design on lane 0,
> so wouldn't you need to mention in DT bindings that the HW has clock
> lanes fixed in position 0 and the accepted values for the 'data_lanes'
> property ranges in the [1-4] interval?

My understanding of video-interfaces.txt which is reference in the DT 
documentation is that the clock is always 0 and the data lanes are 
numbers 1-4 for CSI-2.

> 
> > +
> > +	if (priv->info->init_phtw) {
> > +		/*
> > +		 * This is for H3 ES2.0
> > +		 *
> > +		 * NOTE: Additional logic is needed here when
> > +		 * support for V3H and/or M3-N is added
> > +		 */
> > +		rcar_csi2_write(priv, PHTW_REG, 0x01cc01e2);
> > +		rcar_csi2_write(priv, PHTW_REG, 0x010101e3);
> > +		rcar_csi2_write(priv, PHTW_REG, 0x010101e4);
> > +		rcar_csi2_write(priv, PHTW_REG, 0x01100104);
> > +		rcar_csi2_write(priv, PHTW_REG, 0x01030100);
> > +		rcar_csi2_write(priv, PHTW_REG, 0x01800100);
> > +	}
> > +
> > +	/* Start */
> > +	rcar_csi2_write(priv, PHYPLL_REG, phypll);
> > +
> > +	/* Set frequency range if we have it */
> > +	if (priv->info->csi0clkfreqrange)
> > +		rcar_csi2_write(priv, CSI0CLKFCPR_REG,
> > +				CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange));
> > +
> > +	rcar_csi2_write(priv, PHYCNT_REG, phycnt);
> > +	rcar_csi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN |
> > +			LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP);
> > +	rcar_csi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ);
> > +	rcar_csi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ |
> > +			PHYCNT_RSTZ);
> 
> Nit: from tables 25.[17-20] it seems to me you do not have to re-issue
> PHYCNT_SHUTDOWNZ when writing PHYCNT_RSTZ to PHYCNT_REG.

You are correct, I miss read '.... Here, the ENABLE_0 to ENABLE_3 and
ENABLECLK values set above should be retained' as all previous PHYCNT 
bits should be retained not just the ones explicitly listed. I will give 
this a test and if it still works I will remove it for the next version.

> 
> > +
> > +	return rcar_csi2_wait_phy_start(priv);
> > +}
> > +
> > +static void rcar_csi2_stop(struct rcar_csi2 *priv)
> > +{
> > +	rcar_csi2_write(priv, PHYCNT_REG, 0);
> > +
> > +	rcar_csi2_reset(priv);
> > +}
> > +
> > +static int rcar_csi2_s_stream(struct v4l2_subdev *sd, int enable)
> > +{
> > +	struct rcar_csi2 *priv = sd_to_csi2(sd);
> > +	struct v4l2_subdev *nextsd;
> > +	int ret = 0;
> > +
> > +	mutex_lock(&priv->lock);
> > +
> > +	if (!priv->remote) {
> > +		ret = -ENODEV;
> > +		goto out;
> > +	}
> 
> Can this happen?

Sure, the video source is unbound and as you note bellow the unbind 
callback sets priv->remote = NULL. Or even simpler the driver for the 
video source is not loaded at all so the rcar-csi2 drivers bound 
callback is never called.

> 
> The 'bind' callback sets priv->remote and it gets assigned back to
> NULL only on 'unbind'. Wouldn't it be better to remove the link in the
> media graph and let the system return an EPIPE before calling this?

That would be very complex as some driver in the pipeline (VIN?) would 
have to parse the full graph in DT and somehow with subdevice support 
helpers to traverse the DT port to MC pad mapping using helpers that do 
not exist yet (and are hard to use if the remote subdevice driver is not 
loaded) to build a full view of the pipeline and return -EPIPE if not 
all entities are present in the media graph :-)

[snip]

> > +static int rcar_csi2_parse_v4l2(struct rcar_csi2 *priv,
> > +				struct v4l2_fwnode_endpoint *vep)
> > +{
> > +	unsigned int i;
> > +
> > +	/* Only port 0 endpoint 0 is valid */
> > +	if (vep->base.port || vep->base.id)
> > +		return -ENOTCONN;
> > +
> > +	if (vep->bus_type != V4L2_MBUS_CSI2) {
> > +		dev_err(priv->dev, "Unsupported bus: 0x%x\n", vep->bus_type);
> > +		return -EINVAL;
> > +	}
> > +
> > +	priv->lanes = vep->bus.mipi_csi2.num_data_lanes;
> > +	if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) {
> 
> Is this an HW limitation? Like the 'data_lanes' comment, if it is,
> shouldn't you mention in bindings that the accepted lane numbers is
> limited to the [1,2,4] values.

Yes, see chapter 25.4.8 Lane Setting.

[snip]

> 
> No serious issues though. So when fixed/clarified feel free to append my
> Reviewed-by tag, if relevant at all.

Thanks! I feel I managed to address all of your review comments but 
would still like your confirmation for me to add your tag. Thanks again 
for the review!

-- 
Regards,
Niklas Söderlund



[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux