Hey Marek, On Mon, 1 Aug 2022 at 15:18, Marek Vasut <marex@xxxxxxx> wrote: > > The ICN6211 is capable of deriving its internal PLL clock from either > MIPI DSI HS clock, external REFCLK clock, or even internal oscillator. > Currently supported is only the first option. Add support for external > REFCLK clock input in addition to that. > > There is little difference between these options, except that in case > of MIPI DSI HS clock input, the HS clock are pre-divided by a fixed /4 > divider before being fed to the PLL input, while in case of external > REFCLK, the RECLK clock are fed directly into the PLL input. > > Per exceptionally poor documentation, the REFCLK must be in range of > 10..154 MHz. > > Signed-off-by: Marek Vasut <marex@xxxxxxx> > Cc: Jagan Teki <jagan@xxxxxxxxxxxxxxxxxxxx> > Cc: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> > Cc: Linus Walleij <linus.walleij@xxxxxxxxxx> > Cc: Robert Foss <robert.foss@xxxxxxxxxx> > Cc: Sam Ravnborg <sam@xxxxxxxxxxxx> > Cc: dri-devel@xxxxxxxxxxxxxxxxxxxxx > --- > drivers/gpu/drm/bridge/chipone-icn6211.c | 39 +++++++++++++++++++++--- > 1 file changed, 34 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c > index 65966f280cf4e..7ee1858bab321 100644 > --- a/drivers/gpu/drm/bridge/chipone-icn6211.c > +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c > @@ -11,6 +11,7 @@ > > #include <linux/bitfield.h> > #include <linux/bits.h> > +#include <linux/clk.h> > #include <linux/delay.h> > #include <linux/gpio/consumer.h> > #include <linux/i2c.h> > @@ -151,6 +152,8 @@ struct chipone { > struct regulator *vdd1; > struct regulator *vdd2; > struct regulator *vdd3; > + struct clk *refclk; > + unsigned long refclk_rate; > bool interface_i2c; > }; > > @@ -273,7 +276,10 @@ static void chipone_configure_pll(struct chipone *icn, > * It seems the PLL input clock after applying P pre-divider have > * to be lower than 20 MHz. > */ > - fin = icn->dsi->hs_rate / 4; /* in Hz */ > + if (icn->refclk) > + fin = icn->refclk_rate; > + else > + fin = icn->dsi->hs_rate / 4; /* in Hz */ > > /* Minimum value of P predivider for PLL input in 5..20 MHz */ > p_min = clamp(DIV_ROUND_UP(fin, 20000000), 1U, 31U); > @@ -318,16 +324,18 @@ static void chipone_configure_pll(struct chipone *icn, > best_p_pot = !(best_p & 1); > > dev_dbg(icn->dev, > - "PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in=%d Hz ; DPI f_out=%d Hz\n", > + "PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in(%s)=%d Hz ; DPI f_out=%d Hz\n", > best_p >> best_p_pot, best_p_pot, best_m, best_s + 1, > - min_delta, fin, (fin * best_m) / (best_p << (best_s + 1))); > + min_delta, icn->refclk ? "EXT" : "DSI", fin, > + (fin * best_m) / (best_p << (best_s + 1))); > > ref_div = PLL_REF_DIV_P(best_p >> best_p_pot) | PLL_REF_DIV_S(best_s); > if (best_p_pot) /* Prefer /2 pre-divider */ > ref_div |= PLL_REF_DIV_Pe; > > - /* Clock source selection fixed to MIPI DSI clock lane */ > - chipone_writeb(icn, PLL_CTRL(6), PLL_CTRL_6_MIPI_CLK); > + /* Clock source selection either external clock or MIPI DSI clock lane */ > + chipone_writeb(icn, PLL_CTRL(6), > + icn->refclk ? PLL_CTRL_6_EXTERNAL : PLL_CTRL_6_MIPI_CLK); > chipone_writeb(icn, PLL_REF_DIV, ref_div); > chipone_writeb(icn, PLL_INT(0), best_m); > } > @@ -463,6 +471,11 @@ static void chipone_atomic_pre_enable(struct drm_bridge *bridge, > "failed to enable VDD3 regulator: %d\n", ret); > } > > + ret = clk_prepare_enable(icn->refclk); > + if (ret) > + DRM_DEV_ERROR(icn->dev, > + "failed to enable RECLK clock: %d\n", ret); > + > gpiod_set_value(icn->enable_gpio, 1); > > usleep_range(10000, 11000); > @@ -473,6 +486,8 @@ static void chipone_atomic_post_disable(struct drm_bridge *bridge, > { > struct chipone *icn = bridge_to_chipone(bridge); > > + clk_disable_unprepare(icn->refclk); > + > if (icn->vdd1) > regulator_disable(icn->vdd1); > > @@ -618,6 +633,20 @@ static int chipone_parse_dt(struct chipone *icn) > struct device *dev = icn->dev; > int ret; > > + icn->refclk = devm_clk_get_optional(dev, "refclk"); > + if (IS_ERR(icn->refclk)) { > + ret = PTR_ERR(icn->refclk); > + DRM_DEV_ERROR(dev, "failed to get REFCLK clock: %d\n", ret); > + return ret; > + } else if (icn->refclk) { > + icn->refclk_rate = clk_get_rate(icn->refclk); > + if (icn->refclk_rate < 10000000 || icn->refclk_rate > 154000000) { > + DRM_DEV_ERROR(dev, "REFCLK out of range: %ld Hz\n", > + icn->refclk_rate); > + return -EINVAL; > + } > + } > + > icn->vdd1 = devm_regulator_get_optional(dev, "vdd1"); > if (IS_ERR(icn->vdd1)) { > ret = PTR_ERR(icn->vdd1); > -- > 2.35.1 > This patch looks good to me, but it doesn't apply on drm-misc-next. Do you mind re-spinning it? Rob.