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