Re: [PATCH v2 2/9] clk: ralink: add clock and reset driver for MTMIPS SoCs
From: Stephen Boyd
Date: Thu Apr 13 2023 - 14:55:40 EST
Quoting Sergio Paracuellos (2023-03-20 22:00:27)
> diff --git a/drivers/clk/ralink/clk-mtmips.c b/drivers/clk/ralink/clk-mtmips.c
> new file mode 100644
> index 000000000000..6b4b5ae9384d
> --- /dev/null
> +++ b/drivers/clk/ralink/clk-mtmips.c
> @@ -0,0 +1,985 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MTMIPS SoCs Clock Driver
> + * Author: Sergio Paracuellos <sergio.paracuellos@xxxxxxxxx>
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clk.h>
Drop unused include.
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +
[..]
> +
> +/*
> + * There are drivers for these SoCs that are older than clock driver
> + * and are not prepared for the clock. We don't want the kernel to
> + * disable anything so we add CLK_IS_CRITICAL flag here.
> + */
> +#define CLK_PERIPH(_name, _parent) { \
> + .init = &(struct clk_init_data) { \
const?
> + .name = _name, \
> + .ops = &(const struct clk_ops) { \
Make this into a named variable? Otherwise I suspect the compiler will
want to duplicate it.
> + .recalc_rate = mtmips_pherip_clk_rate \
> + }, \
> + .parent_data = &(const struct clk_parent_data) {\
> + .name = _parent, \
> + .fw_name = _parent \
> + }, \
> + .num_parents = 1, \
> + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL \
Why is everything critical? Put the comment here instead of above the
macro
> + }, \
> +}
> +
[...]
> +
> +static int mtmips_register_pherip_clocks(struct device_node *np,
> + struct clk_hw_onecell_data *clk_data,
> + struct mtmips_clk_priv *priv)
> +{
> + struct clk_hw **hws = clk_data->hws;
> + struct mtmips_clk *sclk;
> + int ret, i;
> +
> + for (i = 0; i < priv->data->num_clk_periph; i++) {
> + int idx = (priv->data->num_clk_base - 1) + i;
> +
> + sclk = &priv->data->clk_periph[i];
> + ret = of_clk_hw_register(np, &sclk->hw);
> + if (ret) {
> + pr_err("Couldn't register peripheral clock %d\n", idx);
> + goto err_clk_unreg;
> + }
> +
> + hws[idx] = &sclk->hw;
> + }
> +
> + return 0;
> +
> +err_clk_unreg:
> + while (--i >= 0) {
> + sclk = &priv->data->clk_periph[i];
> + clk_hw_unregister(&sclk->hw);
> + }
> + return ret;
> +}
> +
> +static inline struct mtmips_clk *to_mtmips_clk(struct clk_hw *hw)
> +{
> + return container_of(hw, struct mtmips_clk, hw);
> +}
> +
> +static unsigned long rt5350_xtal_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 val;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &val);
> + if (!(val & RT5350_CLKCFG0_XTAL_SEL))
> + return 20000000;
> +
> + return 40000000;
> +}
> +
> +static unsigned long rt5350_cpu_recalc_rate(struct clk_hw *hw,
> + unsigned long xtal_clk)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
> + t = (t >> RT5350_SYSCFG0_CPUCLK_SHIFT) & RT5350_SYSCFG0_CPUCLK_MASK;
> +
> + switch (t) {
> + case RT5350_SYSCFG0_CPUCLK_360:
> + return 360000000;
> + case RT5350_SYSCFG0_CPUCLK_320:
> + return 320000000;
> + case RT5350_SYSCFG0_CPUCLK_300:
> + return 300000000;
> + default:
> + BUG();
> + }
> +}
> +
> +static unsigned long rt5350_bus_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + if (parent_rate == 320000000)
> + return parent_rate / 4;
> +
> + return parent_rate / 3;
> +}
> +
> +static unsigned long rt3352_cpu_recalc_rate(struct clk_hw *hw,
> + unsigned long xtal_clk)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
> + t = (t >> RT3352_SYSCFG0_CPUCLK_SHIFT) & RT3352_SYSCFG0_CPUCLK_MASK;
> +
> + switch (t) {
> + case RT3352_SYSCFG0_CPUCLK_LOW:
> + return 384000000;
> + case RT3352_SYSCFG0_CPUCLK_HIGH:
> + return 400000000;
> + default:
> + BUG();
> + }
> +}
> +
> +static unsigned long rt3352_periph_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + return 40000000;
> +}
> +
> +static unsigned long rt3352_bus_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + return parent_rate / 3;
> +}
> +
> +static unsigned long rt305x_xtal_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + return 40000000;
> +}
Register fixed factor and fixed rate clks in software instead of
duplicating the code here.
> +
> +static unsigned long rt305x_cpu_recalc_rate(struct clk_hw *hw,
> + unsigned long xtal_clk)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
> + t = (t >> RT305X_SYSCFG_CPUCLK_SHIFT) & RT305X_SYSCFG_CPUCLK_MASK;
> +
> + switch (t) {
> + case RT305X_SYSCFG_CPUCLK_LOW:
> + return 320000000;
> + case RT305X_SYSCFG_CPUCLK_HIGH:
> + return 384000000;
> + default:
> + BUG();
> + }
> +}
> +
> +static unsigned long rt3883_cpu_recalc_rate(struct clk_hw *hw,
> + unsigned long xtal_clk)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
> + t = (t >> RT3883_SYSCFG0_CPUCLK_SHIFT) & RT3883_SYSCFG0_CPUCLK_MASK;
> +
> + switch (t) {
> + case RT3883_SYSCFG0_CPUCLK_250:
> + return 250000000;
> + case RT3883_SYSCFG0_CPUCLK_384:
> + return 384000000;
> + case RT3883_SYSCFG0_CPUCLK_480:
> + return 480000000;
> + case RT3883_SYSCFG0_CPUCLK_500:
> + return 500000000;
> + default:
> + BUG();
> + }
> +}
> +
> +static unsigned long rt3883_bus_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 ddr2;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
> + ddr2 = t & RT3883_SYSCFG0_DRAM_TYPE_DDR2;
> +
> + switch (parent_rate) {
> + case 250000000:
> + return (ddr2) ? 125000000 : 83000000;
> + case 384000000:
> + return (ddr2) ? 128000000 : 96000000;
> + case 480000000:
> + return (ddr2) ? 160000000 : 120000000;
> + case 500000000:
> + return (ddr2) ? 166000000 : 125000000;
> + default:
> + BUG();
Why? Depending on clk registration order 'parent_rate' could be 0, and
then this will crash the system.
> + }
> +}
> +
> +static unsigned long rt2880_cpu_recalc_rate(struct clk_hw *hw,
> + unsigned long xtal_clk)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
> + t = (t >> RT2880_CONFIG_CPUCLK_SHIFT) & RT2880_CONFIG_CPUCLK_MASK;
> +
> + switch (t) {
> + case RT2880_CONFIG_CPUCLK_250:
> + return 250000000;
> + case RT2880_CONFIG_CPUCLK_266:
> + return 266000000;
> + case RT2880_CONFIG_CPUCLK_280:
> + return 280000000;
> + case RT2880_CONFIG_CPUCLK_300:
> + return 300000000;
> + default:
> + BUG();
> + }
> +}
> +
> +static unsigned long rt2880_bus_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + return parent_rate / 2;
> +}
A fixed factor clk?
> +
> +static u32 mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div)
> +{
> + u64 t;
> +
> + t = ref_rate;
> + t *= mul;
> + do_div(t, div);
Do we really need to do 64-bit math? At the least use div_u64().
> +
> + return t;
> +}
> +
> +static unsigned long mt7620_pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + static const u32 clk_divider[] = { 2, 3, 4, 8 };
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + unsigned long cpu_pll;
> + u32 t;
> + u32 mul;
> + u32 div;
> +
> + regmap_read(sysc, SYSC_REG_CPLL_CONFIG0, &t);
> + if (t & CPLL_CFG0_BYPASS_REF_CLK) {
> + cpu_pll = parent_rate;
> + } else if ((t & CPLL_CFG0_SW_CFG) == 0) {
> + cpu_pll = 600000000;
> + } else {
> + mul = (t >> CPLL_CFG0_PLL_MULT_RATIO_SHIFT) &
> + CPLL_CFG0_PLL_MULT_RATIO_MASK;
> + mul += 24;
> + if (t & CPLL_CFG0_LC_CURFCK)
> + mul *= 2;
> +
> + div = (t >> CPLL_CFG0_PLL_DIV_RATIO_SHIFT) &
> + CPLL_CFG0_PLL_DIV_RATIO_MASK;
> +
> + WARN_ON(div >= ARRAY_SIZE(clk_divider));
WARN_ON_ONCE() so that this doesn't spam the system.
> +
> + cpu_pll = mt7620_calc_rate(parent_rate, mul, clk_divider[div]);
> + }
> +
> + regmap_read(sysc, SYSC_REG_CPLL_CONFIG1, &t);
> + if (t & CPLL_CFG1_CPU_AUX1)
> + return parent_rate;
> +
> + if (t & CPLL_CFG1_CPU_AUX0)
> + return 480000000;
> +
> + return cpu_pll;
> +}
> +
> +static unsigned long mt7620_cpu_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> + u32 mul;
> + u32 div;
> +
> + regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
> + mul = t & CPU_SYS_CLKCFG_CPU_FFRAC_MASK;
> + div = (t >> CPU_SYS_CLKCFG_CPU_FDIV_SHIFT) &
> + CPU_SYS_CLKCFG_CPU_FDIV_MASK;
> +
> + return mt7620_calc_rate(parent_rate, mul, div);
> +}
> +
> +static unsigned long mt7620_bus_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + static const u32 ocp_dividers[16] = {
> + [CPU_SYS_CLKCFG_OCP_RATIO_2] = 2,
> + [CPU_SYS_CLKCFG_OCP_RATIO_3] = 3,
> + [CPU_SYS_CLKCFG_OCP_RATIO_4] = 4,
> + [CPU_SYS_CLKCFG_OCP_RATIO_5] = 5,
> + [CPU_SYS_CLKCFG_OCP_RATIO_10] = 10,
> + };
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> + u32 ocp_ratio;
> + u32 div;
> +
> + if (IS_ENABLED(CONFIG_USB)) {
> + /*
> + * When the CPU goes into sleep mode, the BUS
> + * clock will be too low for USB to function properly.
> + * Adjust the busses fractional divider to fix this
> + */
> + regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
> + t &= ~(CLKCFG_FDIV_MASK | CLKCFG_FFRAC_MASK);
> + t |= CLKCFG_FDIV_USB_VAL | CLKCFG_FFRAC_USB_VAL;
> + regmap_write(sysc, SYSC_REG_CPU_SYS_CLKCFG, t);
Why can't we do this unconditionally? And recalc_rate() shouldn't be
writing registers. It should be calculating the frequency of the clk
based on 'parent_rate' and whatever the hardware is configured for.
> + }
> +
> + regmap_read(sysc, SYSC_REG_CPU_SYS_CLKCFG, &t);
> + ocp_ratio = (t >> CPU_SYS_CLKCFG_OCP_RATIO_SHIFT) &
> + CPU_SYS_CLKCFG_OCP_RATIO_MASK;
> +
> + if (WARN_ON(ocp_ratio >= ARRAY_SIZE(ocp_dividers)))
> + return parent_rate;
> +
> + div = ocp_dividers[ocp_ratio];
> + if (WARN(!div, "invalid divider for OCP ratio %u", ocp_ratio))
Missing newline.
> + return parent_rate;
> +
> + return parent_rate / div;
> +}
> +
> +static unsigned long mt7620_periph_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_CLKCFG0, &t);
> + if (t & CLKCFG0_PERI_CLK_SEL)
> + return parent_rate;
> +
> + return 40000000;
> +}
> +
> +static unsigned long mt76x8_xtal_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct mtmips_clk *clk = to_mtmips_clk(hw);
> + struct regmap *sysc = clk->priv->sysc;
> + u32 t;
> +
> + regmap_read(sysc, SYSC_REG_SYSTEM_CONFIG, &t);
> + if (t & MT7620_XTAL_FREQ_SEL)
> + return 40000000;
> +
> + return 20000000;
> +}
> +
> +static unsigned long mt76x8_cpu_recalc_rate(struct clk_hw *hw,
> + unsigned long xtal_clk)
> +{
> + if (xtal_clk == 40000000)
> + return 580000000;
> +
> + return 575000000;
> +}
> +
> +static unsigned long mt76x8_pcmi2s_recalc_rate(struct clk_hw *hw,
> + unsigned long xtal_clk)
> +{
> + return 480000000;
> +}
Use fixed rate clk.
> +
> +#define CLK_BASE(_name, _parent, _recalc) { \
> + .init = &(struct clk_init_data) { \
const
> + .name = _name, \
> + .ops = &(const struct clk_ops) { \
> + .recalc_rate = _recalc, \
> + }, \
> + .parent_data = &(const struct clk_parent_data) { \
> + .name = _parent, \
> + .fw_name = _parent \
> + }, \
> + .num_parents = _parent ? 1 : 0 \
> + }, \
> +}
> +
[...]
> +
> +static void __init mtmips_clk_init(struct device_node *node)
> +{
> + const struct of_device_id *match;
> + const struct mtmips_clk_data *data;
> + struct mtmips_clk_priv *priv;
> + struct clk_hw_onecell_data *clk_data;
> + int ret, i, count;
> +
> + if (!of_find_property(node, "#clock-cells", NULL)) {
> + pr_err("No '#clock-cells' property found\n");
We don't need to validate the bindings in the driver.
> + return;
> + }
> +
> + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return;
> +
> + priv->sysc = syscon_node_to_regmap(node);
> + if (IS_ERR(priv->sysc)) {
> + pr_err("Could not get sysc syscon regmap\n");
> + goto free_clk_priv;
> + }
> +
> + match = of_match_node(mtmips_of_match, node);
> + if (WARN_ON(!match))
> + return;
> +
> + data = match->data;
> + priv->data = data;
> + count = priv->data->num_clk_base + priv->data->num_clk_periph;
> + clk_data = kzalloc(struct_size(clk_data, hws, count), GFP_KERNEL);
> + if (!clk_data)
> + goto free_clk_priv;
> +
> + ret = mtmips_register_clocks(node, clk_data, priv);
> + if (ret) {
> + pr_err("Couldn't register top clocks\n");
> + goto free_clk_data;
> + }
> +
> + ret = mtmips_register_pherip_clocks(node, clk_data, priv);
> + if (ret) {
> + pr_err("Couldn't register peripheral clocks\n");
> + goto unreg_clk_top;
> + }
> +
> + clk_data->num = count;
> +
> + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
> + if (ret) {
> + pr_err("Couldn't add clk hw provider\n");
> + goto unreg_clk_periph;
> + }
> +
> + return;
> +
> +unreg_clk_periph:
> + for (i = 0; i < priv->data->num_clk_periph; i++) {
> + struct mtmips_clk *sclk = &priv->data->clk_periph[i];
> +
> + clk_hw_unregister(&sclk->hw);
> + }
> +
> +unreg_clk_top:
> + for (i = 0; i < priv->data->num_clk_base; i++) {
> + struct mtmips_clk *sclk = &priv->data->clk_base[i];
> +
> + clk_hw_unregister(&sclk->hw);
> + }
> +
> +free_clk_data:
> + kfree(clk_data);
> +
> +free_clk_priv:
> + kfree(priv);
> +}
> +CLK_OF_DECLARE_DRIVER(rt2880_clk, "ralink,rt2880-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(rt3050_clk, "ralink,rt3050-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(rt3052_clk, "ralink,rt3052-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(rt3352_clk, "ralink,rt3352-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(rt3883_clk, "ralink,rt3883-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(rt5350_clk, "ralink,rt5350-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(mt7620_clk, "ralink,mt7620-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(mt7620a_clk, "ralink,mt7620a-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(mt7628_clk, "ralink,mt7628-sysc", mtmips_clk_init);
> +CLK_OF_DECLARE_DRIVER(mt7688_clk, "ralink,mt7688-sysc", mtmips_clk_init);
Is there any reason why these can't be platform drivers?
> +
[..]
> +
> +static int mtmips_clk_probe(struct platform_device *pdev)
> +{
> + struct device_node *np = pdev->dev.of_node;
> + struct device *dev = &pdev->dev;
> + struct mtmips_clk_priv *priv;
> + int ret;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->sysc = syscon_node_to_regmap(np);
> + if (IS_ERR(priv->sysc)) {
> + ret = PTR_ERR(priv->sysc);
> + dev_err(dev, "Could not get sysc syscon regmap\n");
Use dev_err_probe()?
> + return ret;
> + }
> +
> + ret = mtmips_reset_init(dev, priv->sysc);
> + if (ret) {
> + dev_err(dev, "Could not init reset controller\n");
Use dev_err_probe()?
> + return ret;
> + }
> +
> + return 0;
> +}
> +