[PATCH 2/2] drm: bridge: icn6211: Add support for external REFCLK
Robert Foss
robert.foss at linaro.org
Mon Aug 29 14:54:39 UTC 2022
Hey Marek,
On Mon, 1 Aug 2022 at 15:18, Marek Vasut <marex at denx.de> 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 at denx.de>
> Cc: Jagan Teki <jagan at amarulasolutions.com>
> Cc: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: Robert Foss <robert.foss at linaro.org>
> Cc: Sam Ravnborg <sam at ravnborg.org>
> Cc: dri-devel at lists.freedesktop.org
> ---
> 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.
More information about the dri-devel
mailing list