Re: [PATCH v2 3/3] media: rcar-csi2: Add support for C-PHY on R-Car V4H

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

 



Hejssan!

On Mon, Apr 24, 2023 at 08:59:34PM +0200, Niklas Söderlund wrote:
> @@ -645,6 +755,10 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp,
>  	mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp;
>  	do_div(mbps, lanes * 1000000);
>  
> +	/* Adjust for C-PHY */
> +	if (priv->cphy)
> +		do_div(mbps, 2.8);

This will divide by 2. I suppose that's not intentional??

> +
>  	return mbps;
>  }
>  
> @@ -833,6 +947,170 @@ static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
>  	return 0;
>  }
>  
> +static int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match)
> +{
> +	unsigned int timeout;
> +	u32 status;
> +
> +	for (timeout = 0; timeout <= 10; timeout++) {
> +		status = rcsi2_read(priv, V4H_ST_PHYST_REG);
> +		if ((status & match) == match)
> +			return 0;
> +
> +		usleep_range(1000, 2000);
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps)
> +{
> +	const struct rcsi2_cphy_setting *conf;
> +
> +	for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) {
> +		if (conf->msps > msps)
> +			break;
> +	}
> +
> +	if (!conf->msps) {
> +		dev_err(priv->dev, "Unsupported PHY speed for msps setting (%u Msps)", msps);
> +		return -ERANGE;
> +	}
> +
> +	/* C-PHY specific */
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_COMMON_REG(7), 0x0155);
> +	rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(7), 0x0068);
> +	rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(8), 0x0010);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_LP_0_REG, 0x463c);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_LP_0_REG, 0x463c);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_LP_0_REG, 0x463c);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(0), 0x00d5);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(0), 0x00d5);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(0), 0x00d5);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(1), 0x0013);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(1), 0x0013);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(1), 0x0013);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(5), 0x0013);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(5), 0x0013);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(5), 0x0013);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(6), 0x000a);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(6), 0x000a);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(6), 0x000a);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(2), conf->rx2);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), conf->rx2);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(2), conf->rx2);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(2), 0x0001);
> +	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(2), 0);
> +	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(2), 0x0001);
> +	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(2), 0x0001);
> +	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(2), 0);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), conf->trio0);
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(0), conf->trio0);
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(0), conf->trio0);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(2), conf->trio2);
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(2), conf->trio2);
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(2), conf->trio2);
> +
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(1), conf->trio1);
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(1), conf->trio1);
> +	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(1), conf->trio1);
> +
> +	/*
> +	 * Configure pin-swap.
> +	 * TODO: This registers is not documented yet, the values should depend
> +	 * on the 'clock-lanes' and 'data-lanes' devicetree properties.
> +	 */
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, 0xf5);
> +	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000);
> +
> +	/* Leave Shutdown mode */
> +	rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0));
> +	rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0));
> +
> +	/* Wait for calibration */
> +	if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) {
> +		dev_err(priv->dev, "PHY calibration failed\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* C-PHY setting - analog programing*/
> +	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9), conf->lane29);
> +	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(7), conf->lane27);
> +
> +	return 0;
> +}
> +
> +static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
> +{
> +	const struct rcar_csi2_format *format;
> +	unsigned int msps, lanes;
> +	int ret;
> +
> +	/* Calculate parameters */
> +	format = rcsi2_code_to_fmt(priv->mf.code);

Can this not be NULL? I guess not?

> +
> +	ret = rcsi2_get_active_lanes(priv, &lanes);
> +	if (ret)
> +		return ret;
> +
> +	msps = rcsi2_calc_mbps(priv, format->bpp, lanes);
> +	if (msps < 0)
> +		return msps;
> +
> +	/* Reset LINK and PHY*/
> +	rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0);
> +	rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0);
> +	rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0);

-- 
Hälsningar,

Sakari Ailus



[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