From nobody Tue Sep 16 17:58:42 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0CB7EC3DA7A for ; Sat, 31 Dec 2022 10:48:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235524AbiLaKs0 (ORCPT ); Sat, 31 Dec 2022 05:48:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39000 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231864AbiLaKsC (ORCPT ); Sat, 31 Dec 2022 05:48:02 -0500 Received: from mail-ej1-x644.google.com (mail-ej1-x644.google.com [IPv6:2a00:1450:4864:20::644]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A9ECAD133 for ; Sat, 31 Dec 2022 02:48:00 -0800 (PST) Received: by mail-ej1-x644.google.com with SMTP id ud5so56396576ejc.4 for ; Sat, 31 Dec 2022 02:48:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amarulasolutions.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=1iy2WsPMUIoNX6u9WQ/l0SQoi0Lk5nxPuSrhDYO0lTs=; b=emsOw7kgepZGvr7cmVhAuUy1pxmvNgy5JGtwO2lVuU9cFSxhuic4+z6gUFM2dHW0F5 AUUCTjPEeCS8DPLlzCRsYQwt+FNIpWjUxAO6LHkIhnJ8OtmlV5xAn0tGZLY7nX2GHzim 5twlC9SftCNRcJP/3B55gTQp6QITxA8NgNov0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1iy2WsPMUIoNX6u9WQ/l0SQoi0Lk5nxPuSrhDYO0lTs=; b=7iv+fa1leirrylnLnK1p+R8hVkQ3DD13swC8Hu0qe6kiQly8TFDFt5fOLJjZFOU8bQ 3N7e09nRVPKLFZ3FAVY49JnXflRe213nOKlJOEXRB6GdrwNkpca89vxrp9/pRzjrkjuw FMWsoFEUWsewSOd5/WtJL7A+I9PeOftWrQ9lDv1uvWIEB4EG/J13ZRdUsvrse2Q4HT5v 86AjnW0Yqf0OlcoLK5csOewpy1Cp9+zfL6WakZ43pah8CR+2Nz6KvMGiHMWo4paBvRGN O5EGcGo/Y/fzFkmNQCeM+T/Bc+SFCtQ2WAa3ORWQkT7AUiAfekMarTbHMtj87O0gTjWp kTHA== X-Gm-Message-State: AFqh2krZEpuljgNs94syuEMlFL8wYWebh1A7SrF60lvH8/A81Y/Ie7T1 HuTJsq4fwtn/lgZ1yjFnH9YX++42kgR9vImMgAI= X-Google-Smtp-Source: AMrXdXv8ZevdJwLLV7gy7GY2QLqAScmfeBn3M6bAsFEbIKip0Zwmr9t4Hv/sdHYZcVT4R3xh8pMl1g== X-Received: by 2002:a17:906:85d9:b0:842:1627:77b4 with SMTP id i25-20020a17090685d900b00842162777b4mr29133602ejy.3.1672483678925; Sat, 31 Dec 2022 02:47:58 -0800 (PST) Received: from dario-ThinkPad-T14s-Gen-2i.homenet.telecomitalia.it (host-80-180-23-57.retail.telecomitalia.it. [80.180.23.57]) by smtp.gmail.com with ESMTPSA id z4-20020a17090655c400b0083ffb81f01esm10765438ejp.136.2022.12.31.02.47.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 31 Dec 2022 02:47:58 -0800 (PST) From: Dario Binacchi To: linux-kernel@vger.kernel.org Cc: tommaso.merciai@amarulasolutions.com, linux-amarula@amarulasolutions.com, Chen-Yu Tsai , jagan@amarulasolutions.com, angelo@amarulasolutions.com, anthony@amarulasolutions.com, michael@amarulasolutions.com, Dario Binacchi , Abel Vesa , Fabio Estevam , Michael Turquette , NXP Linux Team , Pengutronix Kernel Team , Sascha Hauer , Shawn Guo , Stephen Boyd , linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org Subject: [RFC PATCH 06/11] clk: imx: pll14xx: add device tree support Date: Sat, 31 Dec 2022 11:47:31 +0100 Message-Id: <20221231104736.12635-7-dario.binacchi@amarulasolutions.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20221231104736.12635-1-dario.binacchi@amarulasolutions.com> References: <20221231104736.12635-1-dario.binacchi@amarulasolutions.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The patch, backwards compatible, extends the driver to initialize the clock directly from the device tree. Signed-off-by: Dario Binacchi --- drivers/clk/imx/clk-pll14xx.c | 220 +++++++++++++++++++++++++++------- 1 file changed, 176 insertions(+), 44 deletions(-) diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 828336873a98..6503005b885a 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -12,6 +12,10 @@ #include #include #include +#include +#include +#include +#include #include #include =20 @@ -36,7 +40,9 @@ =20 struct clk_pll14xx { struct clk_hw hw; - void __iomem *base; + struct imx_clk_reg gnrl_ctl; + struct imx_clk_reg div_ctl0; + struct imx_clk_reg div_ctl1; enum imx_pll14xx_type type; const struct imx_pll14xx_rate_table *rate_table; int rate_count; @@ -90,6 +96,30 @@ struct imx_pll14xx_clk imx_1416x_pll =3D { }; EXPORT_SYMBOL_GPL(imx_1416x_pll); =20 +static void imx_pll14xx_writel(u32 val, const struct imx_clk_reg *reg) +{ + if (reg->base) + writel_relaxed(val, reg->base + reg->offset); + else if (reg->regmap) + regmap_write(reg->regmap, reg->offset, val); + else + pr_err("%s: memory address not set\n", __func__); +} + +static u32 imx_pll14xx_readl(const struct imx_clk_reg *reg) +{ + u32 val =3D 0; + + if (reg->base) + val =3D readl_relaxed(reg->base + reg->offset); + else if (reg->regmap) + regmap_read(reg->regmap, reg->offset, &val); + else + pr_err("%s: memory address not set\n", __func__); + + return val; +} + static const struct imx_pll14xx_rate_table *imx_get_pll_settings( struct clk_pll14xx *pll, unsigned long rate) { @@ -161,11 +191,11 @@ static void imx_pll14xx_calc_settings(struct clk_pll1= 4xx *pll, unsigned long rat return; } =20 - pll_div_ctl0 =3D readl_relaxed(pll->base + DIV_CTL0); + pll_div_ctl0 =3D imx_pll14xx_readl(&pll->div_ctl0); mdiv =3D FIELD_GET(MDIV_MASK, pll_div_ctl0); pdiv =3D FIELD_GET(PDIV_MASK, pll_div_ctl0); sdiv =3D FIELD_GET(SDIV_MASK, pll_div_ctl0); - pll_div_ctl1 =3D readl_relaxed(pll->base + DIV_CTL1); + pll_div_ctl1 =3D imx_pll14xx_readl(&pll->div_ctl1); =20 /* Then see if we can get the desired rate by only adjusting kdiv (glitch= free) */ rate_min =3D pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MIN, prate); @@ -249,13 +279,13 @@ static unsigned long clk_pll14xx_recalc_rate(struct c= lk_hw *hw, struct clk_pll14xx *pll =3D to_clk_pll14xx(hw); u32 mdiv, pdiv, sdiv, kdiv, pll_div_ctl0, pll_div_ctl1; =20 - pll_div_ctl0 =3D readl_relaxed(pll->base + DIV_CTL0); + pll_div_ctl0 =3D imx_pll14xx_readl(&pll->div_ctl0); mdiv =3D FIELD_GET(MDIV_MASK, pll_div_ctl0); pdiv =3D FIELD_GET(PDIV_MASK, pll_div_ctl0); sdiv =3D FIELD_GET(SDIV_MASK, pll_div_ctl0); =20 if (pll->type =3D=3D PLL_1443X) { - pll_div_ctl1 =3D readl_relaxed(pll->base + DIV_CTL1); + pll_div_ctl1 =3D imx_pll14xx_readl(&pll->div_ctl1); kdiv =3D FIELD_GET(KDIV_MASK, pll_div_ctl1); } else { kdiv =3D 0; @@ -277,10 +307,22 @@ static inline bool clk_pll14xx_mp_change(const struct= imx_pll14xx_rate_table *ra =20 static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll) { + struct imx_clk_reg *reg =3D &pll->gnrl_ctl; u32 val; =20 - return readl_poll_timeout(pll->base + GNRL_CTL, val, val & LOCK_STATUS, 0, - LOCK_TIMEOUT_US); + if (reg->base) + return readl_poll_timeout(reg->base + reg->offset, val, + val & LOCK_STATUS, 0, + LOCK_TIMEOUT_US); + + if (reg->regmap) + return regmap_read_poll_timeout(reg->regmap, reg->offset, val, + val & LOCK_STATUS, 0, + LOCK_TIMEOUT_US); + + pr_err("%s: memory address not set\n", __func__); + + return -EIO; } =20 static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate, @@ -298,32 +340,32 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, u= nsigned long drate, return -EINVAL; } =20 - tmp =3D readl_relaxed(pll->base + DIV_CTL0); + tmp =3D imx_pll14xx_readl(&pll->div_ctl0); =20 if (!clk_pll14xx_mp_change(rate, tmp)) { tmp &=3D ~SDIV_MASK; tmp |=3D FIELD_PREP(SDIV_MASK, rate->sdiv); - writel_relaxed(tmp, pll->base + DIV_CTL0); + imx_pll14xx_writel(tmp, &pll->div_ctl0); =20 return 0; } =20 /* Bypass clock and set lock to pll output lock */ - tmp =3D readl_relaxed(pll->base + GNRL_CTL); + tmp =3D imx_pll14xx_readl(&pll->gnrl_ctl); tmp |=3D LOCK_SEL_MASK; - writel_relaxed(tmp, pll->base + GNRL_CTL); + imx_pll14xx_writel(tmp, &pll->gnrl_ctl); =20 /* Enable RST */ tmp &=3D ~RST_MASK; - writel_relaxed(tmp, pll->base + GNRL_CTL); + imx_pll14xx_writel(tmp, &pll->gnrl_ctl); =20 /* Enable BYPASS */ tmp |=3D BYPASS_MASK; - writel(tmp, pll->base + GNRL_CTL); + imx_pll14xx_writel(tmp, &pll->gnrl_ctl); =20 div_val =3D FIELD_PREP(MDIV_MASK, rate->mdiv) | FIELD_PREP(PDIV_MASK, rat= e->pdiv) | FIELD_PREP(SDIV_MASK, rate->sdiv); - writel_relaxed(div_val, pll->base + DIV_CTL0); + imx_pll14xx_writel(div_val, &pll->div_ctl0); =20 /* * According to SPEC, t3 - t2 need to be greater than @@ -335,7 +377,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, uns= igned long drate, =20 /* Disable RST */ tmp |=3D RST_MASK; - writel_relaxed(tmp, pll->base + GNRL_CTL); + imx_pll14xx_writel(tmp, &pll->gnrl_ctl); =20 /* Wait Lock */ ret =3D clk_pll14xx_wait_lock(pll); @@ -344,7 +386,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, uns= igned long drate, =20 /* Bypass */ tmp &=3D ~BYPASS_MASK; - writel_relaxed(tmp, pll->base + GNRL_CTL); + imx_pll14xx_writel(tmp, &pll->gnrl_ctl); =20 return 0; } @@ -359,35 +401,35 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, u= nsigned long drate, =20 imx_pll14xx_calc_settings(pll, drate, prate, &rate); =20 - div_ctl0 =3D readl_relaxed(pll->base + DIV_CTL0); + div_ctl0 =3D imx_pll14xx_readl(&pll->div_ctl0); =20 if (!clk_pll14xx_mp_change(&rate, div_ctl0)) { /* only sdiv and/or kdiv changed - no need to RESET PLL */ div_ctl0 &=3D ~SDIV_MASK; div_ctl0 |=3D FIELD_PREP(SDIV_MASK, rate.sdiv); - writel_relaxed(div_ctl0, pll->base + DIV_CTL0); + imx_pll14xx_writel(div_ctl0, &pll->div_ctl0); =20 - writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), - pll->base + DIV_CTL1); + imx_pll14xx_writel(FIELD_PREP(KDIV_MASK, rate.kdiv), + &pll->div_ctl1); =20 return 0; } =20 /* Enable RST */ - gnrl_ctl =3D readl_relaxed(pll->base + GNRL_CTL); + gnrl_ctl =3D imx_pll14xx_readl(&pll->gnrl_ctl); gnrl_ctl &=3D ~RST_MASK; - writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); + imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl); =20 /* Enable BYPASS */ gnrl_ctl |=3D BYPASS_MASK; - writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); + imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl); =20 div_ctl0 =3D FIELD_PREP(MDIV_MASK, rate.mdiv) | FIELD_PREP(PDIV_MASK, rate.pdiv) | FIELD_PREP(SDIV_MASK, rate.sdiv); - writel_relaxed(div_ctl0, pll->base + DIV_CTL0); + imx_pll14xx_writel(div_ctl0, &pll->div_ctl0); =20 - writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1); + imx_pll14xx_writel(FIELD_PREP(KDIV_MASK, rate.kdiv), &pll->div_ctl1); =20 /* * According to SPEC, t3 - t2 need to be greater than @@ -399,7 +441,7 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, uns= igned long drate, =20 /* Disable RST */ gnrl_ctl |=3D RST_MASK; - writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); + imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl); =20 /* Wait Lock*/ ret =3D clk_pll14xx_wait_lock(pll); @@ -408,7 +450,7 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, uns= igned long drate, =20 /* Bypass */ gnrl_ctl &=3D ~BYPASS_MASK; - writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL); + imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl); =20 return 0; } @@ -423,20 +465,20 @@ static int clk_pll14xx_prepare(struct clk_hw *hw) * RESETB =3D 1 from 0, PLL starts its normal * operation after lock time */ - val =3D readl_relaxed(pll->base + GNRL_CTL); + val =3D imx_pll14xx_readl(&pll->gnrl_ctl); if (val & RST_MASK) return 0; val |=3D BYPASS_MASK; - writel_relaxed(val, pll->base + GNRL_CTL); + imx_pll14xx_writel(val, &pll->gnrl_ctl); val |=3D RST_MASK; - writel_relaxed(val, pll->base + GNRL_CTL); + imx_pll14xx_writel(val, &pll->gnrl_ctl); =20 ret =3D clk_pll14xx_wait_lock(pll); if (ret) return ret; =20 val &=3D ~BYPASS_MASK; - writel_relaxed(val, pll->base + GNRL_CTL); + imx_pll14xx_writel(val, &pll->gnrl_ctl); =20 return 0; } @@ -446,7 +488,7 @@ static int clk_pll14xx_is_prepared(struct clk_hw *hw) struct clk_pll14xx *pll =3D to_clk_pll14xx(hw); u32 val; =20 - val =3D readl_relaxed(pll->base + GNRL_CTL); + val =3D imx_pll14xx_readl(&pll->gnrl_ctl); =20 return (val & RST_MASK) ? 1 : 0; } @@ -460,9 +502,9 @@ static void clk_pll14xx_unprepare(struct clk_hw *hw) * Set RST to 0, power down mode is enabled and * every digital block is reset */ - val =3D readl_relaxed(pll->base + GNRL_CTL); + val =3D imx_pll14xx_readl(&pll->gnrl_ctl); val &=3D ~RST_MASK; - writel_relaxed(val, pll->base + GNRL_CTL); + imx_pll14xx_writel(val, &pll->gnrl_ctl); } =20 static const struct clk_ops clk_pll1416x_ops =3D { @@ -487,13 +529,24 @@ static const struct clk_ops clk_pll1443x_ops =3D { .set_rate =3D clk_pll1443x_set_rate, }; =20 -struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name, - const char *parent_name, void __iomem *base, - const struct imx_pll14xx_clk *pll_clk) +static void imx_clk_hw_unregister_pll14xx(struct clk_hw *hw) { + struct clk_pll14xx *pll =3D to_clk_pll14xx(hw); + + clk_hw_unregister(hw); + kfree(pll); +} + +static struct clk_hw * +imx_clk_hw_register_pll14xx(struct device_node *node, const char *name, + const char *parent_name, + struct imx_clk_reg *iomap, + const struct imx_pll14xx_clk *pll_clk) +{ + struct clk_parent_data pdata =3D { .index =3D 0 }; + struct clk_init_data init =3D { NULL }; struct clk_pll14xx *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; u32 val; =20 @@ -503,7 +556,8 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *de= v, const char *name, =20 init.name =3D name; init.flags =3D pll_clk->flags; - init.parent_names =3D &parent_name; + init.parent_names =3D parent_name ? &parent_name : NULL; + init.parent_data =3D &pdata; init.num_parents =3D 1; =20 switch (pll_clk->type) { @@ -522,19 +576,24 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *= dev, const char *name, return ERR_PTR(-EINVAL); } =20 - pll->base =3D base; + memcpy(&pll->gnrl_ctl, iomap, sizeof(*iomap)); + pll->gnrl_ctl.offset +=3D GNRL_CTL; + memcpy(&pll->div_ctl0, iomap, sizeof(*iomap)); + pll->div_ctl0.offset +=3D DIV_CTL0; + memcpy(&pll->div_ctl1, iomap, sizeof(*iomap)); + pll->div_ctl1.offset +=3D DIV_CTL1; + pll->hw.init =3D &init; pll->type =3D pll_clk->type; pll->rate_table =3D pll_clk->rate_table; pll->rate_count =3D pll_clk->rate_count; =20 - val =3D readl_relaxed(pll->base + GNRL_CTL); + val =3D imx_pll14xx_readl(&pll->gnrl_ctl); val &=3D ~BYPASS_MASK; - writel_relaxed(val, pll->base + GNRL_CTL); + imx_pll14xx_writel(val, &pll->gnrl_ctl); =20 hw =3D &pll->hw; - - ret =3D clk_hw_register(dev, hw); + ret =3D of_clk_hw_register(node, hw); if (ret) { pr_err("failed to register pll %s %d\n", name, ret); kfree(pll); @@ -543,4 +602,77 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *d= ev, const char *name, =20 return hw; } + +struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name, + const char *parent_name, void __iomem *base, + const struct imx_pll14xx_clk *pll_clk) +{ + struct imx_clk_reg iomap =3D {}; + + iomap.base =3D base; + return imx_clk_hw_register_pll14xx(dev_of_node(dev), name, parent_name, + &iomap, pll_clk); +} EXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx); + +/** + * of_imx_pll14xx_clk_setup() - Setup function for imx pll14xx clock + * @node: device node for the clock + */ +static void __init of_imx_pll14xx_clk_setup(struct device_node *node) +{ + struct clk_hw *hw; + struct imx_clk_reg iomap =3D {}; + const char *name =3D node->name; + const struct imx_pll14xx_clk *pll_clk; + const char *pll_type; + u32 val; + + iomap.regmap =3D syscon_regmap_lookup_by_phandle(node, "fsl,anatop"); + if (IS_ERR(iomap.regmap)) { + pr_err("missing regmap for %pOFn\n", node); + return; + } + + if (of_property_read_u32_index(node, "fsl,anatop", 1, &val)) { + pr_err("missing register offset for %pOFn\n", node); + return; + } + + iomap.offset =3D val; + if (of_clk_get_parent_count(node) !=3D 1) { + pr_err("%pOFn must have 1 parent clock\n", node); + return; + } + + of_property_read_string(node, "clock-output-names", &name); + if (of_property_read_string(node, "fsl,type", &pll_type)) { + pr_err("missing 'fsl,type' for %pOFn\n", node); + return; + } + + if (!strcmp(pll_type, "1443x")) { + if (of_property_read_bool(node, "fsl,get-rate-nocache")) + pll_clk =3D &imx_1443x_dram_pll; + else + pll_clk =3D &imx_1443x_pll; + } else if (!strcmp(pll_type, "1416x")) { + pll_clk =3D &imx_1416x_pll; + } else { + pr_err("failed to get pll clock for %pOFn\n", node); + return; + } + + hw =3D imx_clk_hw_register_pll14xx(node, name, NULL, &iomap, pll_clk); + if (IS_ERR(hw)) + return; + + if (of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw)) { + imx_clk_hw_unregister_pll14xx(hw); + return; + } + + pr_debug("name: %s, offset: 0x%x, pll_type: %s\n", name, iomap.offset, + pll_type); +} +CLK_OF_DECLARE(fsl_pll14xx_clk, "fsl,pll14xx-clock", of_imx_pll14xx_clk_se= tup); --=20 2.32.0