From: Stephen Boyd <sboyd@kernel.org>
To: Michael Turquette <mturquette@baylibre.com>,
Yang Xiwen via B4 Relay
<devnull+forbidden405.outlook.com@kernel.org>,
forbidden405@outlook.com
Cc: David Yang <mmyangfl@gmail.com>,
Igor Opaniuk <igor.opaniuk@foundries.io>,
Jorge Ramirez-Ortiz Gmail <jorge.ramirez.ortiz@gmail.com>,
linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org,
Yang Xiwen <forbidden405@outlook.com>
Subject: Re: [PATCH RFC 2/2] clk: hisilicon: add support for PLL
Date: Wed, 10 Apr 2024 23:59:46 -0700 [thread overview]
Message-ID: <8b517c5b165d2be77eaf02af1e031325.sboyd@kernel.org> (raw)
In-Reply-To: <20240225-pll-v1-2-fad6511479c6@outlook.com>
Quoting Yang Xiwen via B4 Relay (2024-02-24 08:56:10)
> diff --git a/drivers/clk/hisilicon/clk-pll.c b/drivers/clk/hisilicon/clk-pll.c
> new file mode 100644
> index 000000000000..c5c07a65fcf4
> --- /dev/null
> +++ b/drivers/clk/hisilicon/clk-pll.c
> @@ -0,0 +1,171 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * PLL driver for HiSilicon SoCs
> + *
> + * Copyright 2024 (c) Yang Xiwen <forbidden405@outlook.com>
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +
> +#include "clk.h"
> +
> +/* PLL has two conf regs in total */
> +#define HISI_PLL_CFG(n) ((n) * 4)
Isn't HISI_PLL_CFG1 or HISI_PLL_CFG0 shorter then?
> +
> +/* reg 0 definitions */
> +#define HISI_PLL_FRAC GENMASK(23, 0)
> +#define HISI_PLL_POSTDIV1 GENMASK(26, 24)
> +#define HISI_PLL_POSTDIV2 GENMASK(30, 28)
> +
> +/* reg 1 definitions */
> +#define HISI_PLL_FBDIV GENMASK(11, 0)
> +#define HISI_PLL_REFDIV GENMASK(17, 12)
> +#define HISI_PLL_PD BIT(20)
> +#define HISI_PLL_FOUTVCOPD BIT(21)
> +#define HISI_PLL_FOUT4PHASEPD BIT(22)
> +#define HISI_PLL_FOUTPOSTDIVPD BIT(23)
> +#define HISI_PLL_DACPD BIT(24)
> +#define HISI_PLL_DSMPD BIT(25)
> +#define HISI_PLL_BYPASS BIT(26)
> +
> +/*
> + * Datasheet said the maximum is 3.2GHz,
> + * but tests show it can be very high
Sounds like you're over-clocking. Just follow the datasheet please.
> + *
> + * Leave some margin here (8 GHz should be fine)
> + */
> +#define HISI_PLL_FOUTVCO_MAX_RATE 8000000000
> +/* 800 MHz */
> +#define HISI_PLL_FOUTVCO_MIN_RATE 800000000
> +
> +struct hisi_pll {
> + struct clk_hw hw;
> + void __iomem *base;
> + u8 postdiv1, postdiv2, refdiv;
> + u32 divisor;
> +};
> +
> +#define to_hisi_pll(_hw) container_of(_hw, struct hisi_pll, hw)
> +
> +static int hisi_pll_prepare(struct clk_hw *hw)
> +{
> + struct hisi_pll *pll = to_hisi_pll(hw);
> + u32 reg;
> +
> + reg = readl(pll->base + HISI_PLL_CFG(0));
> + pll->postdiv1 = FIELD_GET(HISI_PLL_POSTDIV1, reg);
> + pll->postdiv2 = FIELD_GET(HISI_PLL_POSTDIV2, reg);
> + // We don't use frac, clear it
Kernel comments are /* like this */
> + reg &= ~HISI_PLL_FRAC;
> + writel(reg, pll->base + HISI_PLL_CFG(0));
> +
> + reg = readl(pll->base + HISI_PLL_CFG(1));
> + pll->refdiv = FIELD_GET(HISI_PLL_REFDIV, reg);
> +
> + pll->divisor = pll->refdiv * pll->postdiv1 * pll->postdiv2;
> +
> + // return -EINVAL if boot loader does not init PLL correctly
Yeah we got that by reading the code, no comment needed.
> + if (pll->divisor == 0) {
> + pr_err("%s: PLLs are not initialized by boot loader correctly!\n", __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int hisi_pll_set_rate(struct clk_hw *hw, ulong rate, ulong parent_rate)
> +{
> + struct hisi_pll *pll = to_hisi_pll(hw);
> + u64 fbdiv = rate * pll->divisor;
> + u32 reg;
> +
> + do_div(fbdiv, parent_rate);
> +
> + reg = readl(pll->base + HISI_PLL_CFG(1));
> + reg &= ~HISI_PLL_FBDIV;
> + reg |= FIELD_PREP(HISI_PLL_FBDIV, fbdiv);
> + writel(reg, pll->base + HISI_PLL_CFG(1));
> +
> + /* TODO: wait for PLL lock? */
Yes?
> +
> + return 0;
> +}
> +
> +static int hisi_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
> + struct hisi_pll *pll = to_hisi_pll(hw);
> + u64 vco, ref_rate = req->best_parent_rate;
> +
> + if (ref_rate == 0)
> + return -EINVAL;
> +
> + do_div(ref_rate, pll->refdiv);
> + vco = clamp(req->rate * (pll->postdiv1 * pll->postdiv2),
> + HISI_PLL_FOUTVCO_MIN_RATE, HISI_PLL_FOUTVCO_MAX_RATE);
> + vco = rounddown(vco, ref_rate);
> + if (vco < HISI_PLL_FOUTVCO_MIN_RATE)
> + vco += ref_rate;
> +
> + do_div(vco, pll->postdiv1 * pll->postdiv2);
> + req->rate = vco;
> +
> + return 0;
> +}
> +
> +static ulong hisi_pll_recalc_rate(struct clk_hw *hw, ulong parent_rate)
> +{
> + struct hisi_pll *pll = to_hisi_pll(hw);
> + u32 reg, fbdiv;
> +
> + reg = readl(pll->base + HISI_PLL_CFG(1));
> + fbdiv = FIELD_GET(HISI_PLL_FBDIV, reg);
> + parent_rate *= fbdiv;
> + do_div(parent_rate, pll->divisor);
> +
> + return parent_rate;
> +}
> +
> +static const struct clk_ops hisi_pll_ops = {
> + .prepare = hisi_pll_prepare,
> + .set_rate = hisi_pll_set_rate,
> + .determine_rate = hisi_pll_determine_rate,
> + .recalc_rate = hisi_pll_recalc_rate,
> +};
> +
> +/*
> + * devm_hisi_pll_register - register a HiSilicon PLL
Use kernel-doc please https://docs.kernel.org/doc-guide/kernel-doc.html
> + *
> + * @dev: clk provider
> + * @name: clock name
> + * @parent_name: parent clock, usually 24MHz OSC
> + * #flags: CCF common flags
> + * @reg: register address
Missing Return:
> + */
> +struct clk *devm_clk_register_hisi_pll(struct device *dev, const char *name, const char *parent,
> + unsigned int flags, void __iomem *reg)
> +{
> + struct hisi_pll *pll;
> + struct clk_init_data init;
> +
> + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
> + if (!pll)
> + return ERR_PTR(-ENOMEM);
> +
> + if (!parent)
> + return ERR_PTR(-EINVAL);
> +
> + init.name = name;
> + init.ops = &hisi_pll_ops;
> + init.flags = flags;
> + init.parent_names = &parent;
> + init.num_parents = 1;
> +
> + pll->base = reg;
> + pll->hw.init = &init;
> +
> + return devm_clk_register(dev, &pll->hw);
> +}
> +EXPORT_SYMBOL_GPL(devm_clk_register_hisi_pll);
> diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
> index 7a9b42e1b027..8c59f3927152 100644
> --- a/drivers/clk/hisilicon/clk.h
> +++ b/drivers/clk/hisilicon/clk.h
> @@ -103,6 +103,14 @@ struct hisi_gate_clock {
> const char *alias;
> };
>
> +struct hisi_pll_clock {
> + unsigned int id;
> + const char *name;
> + const char *parent_name;
No string parent names for new code. Use struct clk_parent_data or
clk_hw directly.
next prev parent reply other threads:[~2024-04-11 6:59 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-24 16:56 [PATCH RFC 0/2] clk: hisilicon: add support for PLL Yang Xiwen
2024-02-24 16:56 ` Yang Xiwen via B4 Relay
2024-02-24 16:56 ` [PATCH RFC 1/2] clk: hisilicon: rename hi3519 PLL registration function Yang Xiwen
2024-02-24 16:56 ` Yang Xiwen via B4 Relay
2024-04-11 6:52 ` Stephen Boyd
2024-04-11 7:44 ` Yang Xiwen
2024-04-11 7:53 ` Stephen Boyd
2024-04-11 10:31 ` Yang Xiwen
2024-04-12 3:03 ` Stephen Boyd
2024-02-24 16:56 ` [PATCH RFC 2/2] clk: hisilicon: add support for PLL Yang Xiwen
2024-02-24 16:56 ` Yang Xiwen via B4 Relay
2024-02-27 3:06 ` kernel test robot
2024-04-11 6:59 ` Stephen Boyd [this message]
2024-04-11 7:54 ` Yang Xiwen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8b517c5b165d2be77eaf02af1e031325.sboyd@kernel.org \
--to=sboyd@kernel.org \
--cc=devnull+forbidden405.outlook.com@kernel.org \
--cc=forbidden405@outlook.com \
--cc=igor.opaniuk@foundries.io \
--cc=jorge.ramirez.ortiz@gmail.com \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mmyangfl@gmail.com \
--cc=mturquette@baylibre.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.